/* Expand a template with {word} tokens from the given options objects function template(pattern: String, ...options): Uri */ static EjsUri *uri_template(Ejs *ejs, EjsUri *up, int argc, EjsObj **argv) { EjsArray *options; EjsObj *obj, *value; MprBuf *buf; cchar *pattern, *cp, *ep, *str; char *token; int i, len; pattern = ejsToMulti(ejs, argv[0]); options = (EjsArray*) argv[1]; buf = mprCreateBuf(-1, -1); for (cp = pattern; *cp; cp++) { if (*cp == '~' && (cp == pattern || cp[-1] != '\\')) { for (i = 0; i < options->length; i++) { obj = options->data[i]; if ((value = ejsGetPropertyByName(ejs, obj, N(NULL, "scriptName"))) != 0 && ejsIsDefined(ejs, value)) { str = ejsToMulti(ejs, value); if (str && *str) { mprPutStringToBuf(buf, str); break; } else { value = 0; } } } } else if (*cp == '{' && (cp == pattern || cp[-1] != '\\')) { if ((ep = strchr(++cp, '}')) != 0) { len = (int) (ep - cp); token = mprMemdup(cp, len + 1); token[len] = '\0'; value = 0; for (i = 0; i < options->length; i++) { obj = options->data[i]; if ((value = ejsGetPropertyByName(ejs, obj, N(NULL, token))) != 0 && ejsIsDefined(ejs, value)) { str = ejsToMulti(ejs, value); if (str && *str) { mprPutStringToBuf(buf, str); break; } else { value = 0; } } } if (!ejsIsDefined(ejs, value)) { // MOB - remove this. Should not be erasing the prior "/" if (cp >= &pattern[2] && cp[-2] == '/') { mprAdjustBufEnd(buf, -1); } } cp = ep; } } else { mprPutCharToBuf(buf, *cp); } } mprAddNullToBuf(buf); return ejsCreateUriFromAsc(ejs, mprGetBufStart(buf)); }
int ecOpenMemoryStream(EcLexer *lp, const uchar *buf, int len) { EcMemStream *ms; int c; ms = mprAllocObjZeroed(lp->input, EcMemStream); if (ms == 0) { return MPR_ERR_NO_MEMORY; } ms->stream.lineNumber = 0; ms->stream.buf = mprMemdup(ms, buf, len); ms->stream.nextChar = ms->stream.buf; ms->stream.end = &ms->stream.buf[len]; ms->stream.currentLine = ms->stream.buf; ms->stream.lineNumber = 1; ms->stream.compiler = lp->compiler; mprFree(lp->input->stream); lp->input->stream = (EcStream*) ms; lp->input->putBack = 0; lp->input->token = 0; lp->input->state = 0; lp->input->next = 0; /* * Initialize the stream line and column data. */ c = getNextChar(&ms->stream); putBackChar(&ms->stream, c); return 0; }
/* * Called to complete any token */ static int finishToken(EcToken *tp, int tokenId, int subId, int groupMask) { EcStream *stream; char *end; int len; mprAssert(tp); stream = tp->stream; mprAssert(stream); tp->tokenId = tokenId; tp->subId = subId; tp->groupMask = groupMask; /* * TODO optimize this. Would be really nice to tokenize the input and just return pointers into the stream->buf */ if (tp->currentLine == 0) { setTokenCurrentLine(tp); } if (tp->currentLine) { end = strchr(tp->currentLine, '\n'); len = end ? (int) (end - tp->currentLine) : (int) strlen(tp->currentLine); tp->currentLine = (char*) mprMemdup(tp, tp->currentLine, len + 1); tp->currentLine[len] = '\0'; mprAssert(tp->currentLine); mprLog(tp, 9, "Lex lineNumber %d \"%s\" %s", tp->lineNumber, tp->text, tp->currentLine); } return tokenId; }
EjsTypeHelpers *ejsGetObjectHelpers(Ejs *ejs) { /* * TODO OPT. Does every type need a copy -- NO. But the loader uses this and allows * native types to selectively override. See samples/types/native. */ return (EjsTypeHelpers*) mprMemdup(ejs, ejs->objectHelpers, sizeof(EjsTypeHelpers)); }
EjsTypeHelpers *ejsGetBlockHelpers(Ejs *ejs) { return (EjsTypeHelpers*) mprMemdup(ejs, ejs->blockHelpers, sizeof(EjsTypeHelpers)); }
EjsTypeHelpers *ejsGetDefaultHelpers(Ejs *ejs) { return (EjsTypeHelpers*) mprMemdup(ejs, ejs->defaultHelpers, sizeof(EjsTypeHelpers)); }
PUBLIC int ecGetToken(EcCompiler *cp) { EcToken *tp; EcStream *stream; int c; if ((tp = getLexToken(cp)) == NULL) { return T_ERR; } if (tp->tokenId) { return tp->tokenId; } stream = cp->stream; while (1) { c = getNextChar(stream); /* Overloadable operators + - ~ * / % < > <= >= == << >> >>> & | === != !== TODO FUTURE, we could allow also: ".", "[", "(" and unary !, ^ */ switch (c) { default: if (isdigit((uchar) c)) { return makeNumberToken(cp, tp, c); } else if (c == '\\') { c = getNextChar(stream); if (c == '\n') { break; } putBackChar(stream, c); c = '\n'; } if (isalpha((uchar) c) || c == '_' || c == '\\' || c == '$') { return makeAlphaToken(cp, tp, c); } return makeToken(tp, 0, T_ERR, 0); case -1: return makeToken(tp, 0, T_ERR, 0); case 0: if (stream->flags & EC_STREAM_EOL) { return makeToken(tp, 0, T_NOP, 0); } return makeToken(tp, 0, T_EOF, 0); case ' ': case '\f': case '\t': case '\v': case 0xA0: /* No break space */ break; case '\r': case '\n': break; case '"': case '\'': return makeQuotedToken(cp, tp, c); case '#': return makeToken(tp, c, T_HASH, 0); case '[': // EJS extension to consider this an operator return makeToken(tp, c, T_LBRACKET, G_OPERATOR); case ']': return makeToken(tp, c, T_RBRACKET, 0); case '(': // EJS extension to consider this an operator return makeToken(tp, c, T_LPAREN, G_OPERATOR); case ')': return makeToken(tp, c, T_RPAREN, 0); case '{': return makeToken(tp, c, T_LBRACE, 0); case '}': return makeToken(tp, c, T_RBRACE, 0); case '@': return makeToken(tp, c, T_AT, 0); case ';': return makeToken(tp, c, T_SEMICOLON, 0); case ',': return makeToken(tp, c, T_COMMA, 0); case '?': return makeToken(tp, c, T_QUERY, 0); case '~': return makeToken(tp, c, T_TILDE, G_OPERATOR); case '+': c = getNextChar(stream); if (c == '+') { addCharToToken(tp, '+'); return makeToken(tp, c, T_PLUS_PLUS, G_OPERATOR); } else if (c == '=') { addCharToToken(tp, '+'); return makeSubToken(tp, c, T_ASSIGN, T_PLUS_ASSIGN, G_OPERATOR | G_COMPOUND_ASSIGN); } putBackChar(stream, c); return makeToken(tp, '+', T_PLUS, G_OPERATOR); case '-': c = getNextChar(stream); if (isdigit((uchar) c)) { putBackChar(stream, c); return makeToken(tp, '-', T_MINUS, G_OPERATOR); } else if (c == '-') { addCharToToken(tp, '-'); return makeToken(tp, c, T_MINUS_MINUS, G_OPERATOR); } else if (c == '=') { addCharToToken(tp, '-'); return makeSubToken(tp, c, T_ASSIGN, T_MINUS_ASSIGN, G_OPERATOR | G_COMPOUND_ASSIGN); } putBackChar(stream, c); return makeToken(tp, '-', T_MINUS, G_OPERATOR); case '*': c = getNextChar(stream); if (c == '=') { addCharToToken(tp, '*'); return makeSubToken(tp, c, T_ASSIGN, T_MUL_ASSIGN, G_OPERATOR | G_COMPOUND_ASSIGN); } putBackChar(stream, c); return makeToken(tp, '*', T_MUL, G_OPERATOR); case '/': c = getNextChar(stream); if (c == '=') { addCharToToken(tp, '/'); return makeSubToken(tp, c, T_ASSIGN, T_DIV_ASSIGN, G_OPERATOR | G_COMPOUND_ASSIGN); } else if (c == '>') { addCharToToken(tp, '/'); return makeToken(tp, c, T_SLASH_GT, G_OPERATOR); } else if (c == '*' || c == '/') { /* C and C++ comments */ if (getComment(cp, tp, c) < 0) { return tp->tokenId; } /* Doc comments are: [slash]**. The second "*' becomes the first char of the comment. Don't regard: [slash]*** (three stars) as a comment. */ if (cp->doc) { if (tp->text && tp->text[0] == '*' && tp->text[1] != '*') { cp->docToken = mprMemdup(tp->text, tp->length * sizeof(wchar)); } } initializeToken(tp, stream); break; } putBackChar(stream, c); return makeToken(tp, '/', T_DIV, G_OPERATOR); case '%': c = getNextChar(stream); if (c == '=') { addCharToToken(tp, '%'); return makeSubToken(tp, c, T_ASSIGN, T_MOD_ASSIGN, G_OPERATOR | G_COMPOUND_ASSIGN); } putBackChar(stream, c); return makeToken(tp, '%', T_MOD, G_OPERATOR); case '.': c = getNextChar(stream); if (c == '.') { c = getNextChar(stream); if (c == '.') { addStringToToken(tp, ".."); return makeToken(tp, c, T_ELIPSIS, 0); } putBackChar(stream, c); addCharToToken(tp, '.'); return makeToken(tp, '.', T_DOT_DOT, 0); #if FUTURE } else if (c == '<') { addCharToToken(tp, '.'); return makeToken(tp, c, T_DOT_LESS, 0); #endif } else if (isdigit((uchar) c)) { putBackChar(stream, c); return makeNumberToken(cp, tp, '.'); } putBackChar(stream, c); // EJS extension to consider this an operator return makeToken(tp, '.', T_DOT, G_OPERATOR); case ':': c = getNextChar(stream); if (c == ':') { addCharToToken(tp, ':'); return makeToken(tp, c, T_COLON_COLON, 0); } putBackChar(stream, c); return makeToken(tp, ':', T_COLON, 0); case '!': c = getNextChar(stream); if (c == '=') { c = getNextChar(stream); if (c == '=') { addStringToToken(tp, "!="); return makeToken(tp, c, T_STRICT_NE, G_OPERATOR); } putBackChar(stream, c); addCharToToken(tp, '!'); return makeToken(tp, '=', T_NE, G_OPERATOR); } putBackChar(stream, c); return makeToken(tp, '!', T_LOGICAL_NOT, G_OPERATOR); case '&': c = getNextChar(stream); if (c == '&') { addCharToToken(tp, '&'); c = getNextChar(stream); if (c == '=') { addCharToToken(tp, '&'); return makeSubToken(tp, '=', T_ASSIGN, T_LOGICAL_AND_ASSIGN, G_OPERATOR | G_COMPOUND_ASSIGN); } putBackChar(stream, c); return makeToken(tp, '&', T_LOGICAL_AND, G_OPERATOR); } else if (c == '=') { addCharToToken(tp, '&'); return makeSubToken(tp, c, T_ASSIGN, T_BIT_AND_ASSIGN, G_OPERATOR | G_COMPOUND_ASSIGN); } putBackChar(stream, c); return makeToken(tp, '&', T_BIT_AND, G_OPERATOR); case '<': c = getNextChar(stream); if (c == '=') { addCharToToken(tp, '<'); return makeToken(tp, c, T_LE, G_OPERATOR); } else if (c == '<') { c = getNextChar(stream); if (c == '=') { addStringToToken(tp, "<<"); return makeSubToken(tp, c, T_ASSIGN, T_LSH_ASSIGN, G_OPERATOR | G_COMPOUND_ASSIGN); } putBackChar(stream, c); addCharToToken(tp, '<'); return makeToken(tp, c, T_LSH, G_OPERATOR); } else if (c == '/') { addCharToToken(tp, '<'); return makeToken(tp, c, T_LT_SLASH, 0); } putBackChar(stream, c); return makeToken(tp, '<', T_LT, G_OPERATOR); case '=': c = getNextChar(stream); if (c == '=') { c = getNextChar(stream); if (c == '=') { addStringToToken(tp, "=="); return makeToken(tp, c, T_STRICT_EQ, G_OPERATOR); } putBackChar(stream, c); addCharToToken(tp, '='); return makeToken(tp, c, T_EQ, G_OPERATOR); } putBackChar(stream, c); return makeToken(tp, '=', T_ASSIGN, G_OPERATOR); case '>': c = getNextChar(stream); if (c == '=') { addCharToToken(tp, '<'); return makeToken(tp, c, T_GE, G_OPERATOR); } else if (c == '>') { c = getNextChar(stream); if (c == '=') { addStringToToken(tp, ">>"); return makeSubToken(tp, c, T_ASSIGN, T_RSH_ASSIGN, G_OPERATOR | G_COMPOUND_ASSIGN); } else if (c == '>') { c = getNextChar(stream); if (c == '=') { addStringToToken(tp, ">>>"); return makeSubToken(tp, c, T_ASSIGN, T_RSH_ZERO_ASSIGN, G_OPERATOR | G_COMPOUND_ASSIGN); } putBackChar(stream, c); addStringToToken(tp, ">>"); return makeToken(tp, '>', T_RSH_ZERO, G_OPERATOR); } putBackChar(stream, c); addCharToToken(tp, '>'); return makeToken(tp, '>', T_RSH, G_OPERATOR); } putBackChar(stream, c); return makeToken(tp, '>', T_GT, G_OPERATOR); case '^': c = getNextChar(stream); if (c == '^') { addCharToToken(tp, '^'); c = getNextChar(stream); if (c == '=') { addCharToToken(tp, '^'); return makeSubToken(tp, '=', T_ASSIGN, T_LOGICAL_XOR_ASSIGN, G_OPERATOR | G_COMPOUND_ASSIGN); } putBackChar(stream, c); return makeToken(tp, '^', T_LOGICAL_XOR, G_OPERATOR); } else if (c == '=') { addCharToToken(tp, '^'); return makeSubToken(tp, '=', T_ASSIGN, T_BIT_XOR_ASSIGN, G_OPERATOR | G_COMPOUND_ASSIGN); } putBackChar(stream, c); return makeToken(tp, '^', T_BIT_XOR, G_OPERATOR); case '|': c = getNextChar(stream); if (c == '|') { addCharToToken(tp, '|'); c = getNextChar(stream); if (c == '=') { addCharToToken(tp, '|'); return makeSubToken(tp, '=', T_ASSIGN, T_LOGICAL_OR_ASSIGN, G_OPERATOR | G_COMPOUND_ASSIGN); } putBackChar(stream, c); return makeToken(tp, '|', T_LOGICAL_OR, G_OPERATOR); } else if (c == '=') { addCharToToken(tp, '|'); return makeSubToken(tp, '=', T_ASSIGN, T_BIT_OR_ASSIGN, G_OPERATOR | G_COMPOUND_ASSIGN); } putBackChar(stream, c); return makeToken(tp, '|', T_BIT_OR, G_OPERATOR); } } }