PUBLIC int ecGetRegExpToken(EcCompiler *cp, wchar *prefix) { EcToken *token, *tp; EcStream *stream; wchar *pp; int c; stream = cp->stream; tp = token = cp->token; assert(tp != 0); initializeToken(tp, stream); for (pp = prefix; pp && *pp; pp++) { addCharToToken(tp, *pp); } while (1) { c = getNextChar(stream); switch (c) { 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 '/': addCharToToken(tp, '/'); while (1) { c = getNextChar(stream); if (c != 'g' && c != 'i' && c != 'm' && c != 'y' && c != 'x' && c != 'X' && c != 'U' && c != 's') { putBackChar(stream, c); break; } addCharToToken(tp, c); } return makeToken(tp, 0, T_REGEXP, 0); case '\\': c = getNextChar(stream); if (c == '\r' || c == '\n' || c == 0) { ecError(cp, "Warning", &stream->loc, "Illegal newline in regular expression"); return makeToken(tp, 0, T_ERR, 0); } addCharToToken(tp, '\\'); addCharToToken(tp, c); break; case '\r': case '\n': ecError(cp, "Warning", &stream->loc, "Illegal newline in regular expression"); return makeToken(tp, 0, T_ERR, 0); default: addCharToToken(tp, c); } } }
static void compileError(EcCompiler *cp, cchar *fmt, ...) { va_list args; cp->errorCount++; cp->error = 1; va_start(args, fmt); ecError(cp, "Error", NULL, fmt, args); va_end(args); }
/* C, C++ and doc style comments. Return token or zero for no token. */ static int getComment(EcCompiler *cp, EcToken *tp, int c) { EcStream *stream; int form, startLine; startLine = cp->stream->loc.lineNumber; stream = cp->stream; form = c; for (form = c; c > 0;) { c = getNextChar(stream); if (c <= 0) { /* Unterminated Comment */ addFormattedStringToToken(tp, "Unterminated comment starting on line %d", startLine); makeToken(tp, 0, form == '/' ? T_EOF: T_ERR, 0); return 1; } if (form == '/') { if (c == '\n' || c == '\r') { break; } } else { if (c == '*') { c = getNextChar(stream); if (c == '/') { break; } addCharToToken(tp, '*'); putBackChar(stream, c); } else if (c == '/') { c = getNextChar(stream); if (c == '*') { /* Nested comment */ if (cp->warnLevel > 0) { ecError(cp, "Warning", &stream->loc, "Possible nested comment"); } } addCharToToken(tp, '/'); } } addCharToToken(tp, c); } return 0; }
static int compileInner(EcCompiler *cp, int argc, char **argv) { Ejs *ejs; EjsModule *mp; MprList *nodes; EjsBlock *block; EcLocation loc; cchar *ext; char *msg; int next, i, j, nextModule, lflags, rc, paused; ejs = cp->ejs; if ((nodes = mprCreateList(-1, 0)) == 0) { return EJS_ERR; } cp->nodes = nodes; /* Warn about source files mentioned multiple times. TODO OPT. This is slow. */ for (i = 0; i < argc; i++) { for (j = 0; j < argc; j++) { if (i == j) { continue; } if (mprSamePath(argv[i], argv[j])) { compileError(cp, "Loading source %s multiple times. Ignoring extra copies.", argv[i]); return EJS_ERR; } } if (cp->outputFile && mprSamePath(cp->outputFile, argv[i])) { compileError(cp, "Output file is the same as input file: %s", argv[i]); return EJS_ERR; } } /* Compile source files and load any module files */ for (i = 0; i < argc && !cp->fatalError; i++) { ext = mprGetPathExt(argv[i]); if (scasecmp(ext, "mod") == 0 || scasecmp(ext, BIT_SHOBJ) == 0) { nextModule = mprGetListLength(ejs->modules); lflags = cp->strict ? EJS_LOADER_STRICT : 0; if ((rc = ejsLoadModule(cp->ejs, ejsCreateStringFromAsc(ejs, argv[i]), -1, -1, lflags)) < 0) { msg = sfmt("Error initializing module %s\n%s", argv[i], ejsGetErrorMsg(cp->ejs, 1)); memset(&loc, 0, sizeof(EcLocation)); loc.filename = sclone(argv[i]); if (rc == MPR_ERR_CANT_INITIALIZE) { ecError(cp, "Error", &loc, msg); } else { ecError(cp, "Error", &loc, msg); } cp->nodes = NULL; return EJS_ERR; } if (cp->merge) { /* If merging, we must emit the loaded module into the output. So add to the compiled modules list. */ for (next = nextModule; (mp = mprGetNextItem(ejs->modules, &next)) != 0; ) { if (mprLookupItem(cp->modules, mp) < 0 && mprAddItem(cp->modules, mp) < 0) { compileError(cp, "Can't add module %s", mp->name); } } } mprAddItem(nodes, 0); } else { mprAssert(!MPR->marking); paused = ejsBlockGC(ejs); mprAddItem(nodes, ecParseFile(cp, argv[i])); ejsUnblockGC(ejs, paused); } mprAssert(!MPR->marking); } mprAssert(ejs->result == 0 || (MPR_GET_GEN(MPR_GET_MEM(ejs->result)) != MPR->heap->dead)); /* Allocate the eval frame stack. This is used for property lookups. We have one dummy block at the top always. */ block = ejsCreateBlock(ejs, 0); mprSetName(block, "Compiler"); ejsPushBlock(ejs, block); /* Process the internal representation and generate code */ paused = ejsBlockGC(ejs); if (!cp->parseOnly && cp->errorCount == 0) { ecResetParser(cp); if (ecAstProcess(cp) < 0) { ejsPopBlock(ejs); cp->nodes = NULL; ejsUnblockGC(ejs, paused); return EJS_ERR; } if (cp->errorCount == 0) { ecResetParser(cp); if (ecCodeGen(cp) < 0) { ejsPopBlock(ejs); cp->nodes = NULL; ejsUnblockGC(ejs, paused); return EJS_ERR; } } } ejsPopBlock(ejs); mprAssert(ejs->result == 0 || (MPR_GET_GEN(MPR_GET_MEM(ejs->result)) != MPR->heap->dead)); /* Add compiled modules to the interpreter */ for (next = 0; ((mp = (EjsModule*) mprGetNextItem(cp->modules, &next)) != 0); ) { ejsAddModule(cp->ejs, mp); } cp->nodes = NULL; ejsUnblockGC(ejs, paused); if (!paused) { mprYield(0); } mprAssert(ejs->result == 0 || (MPR_GET_GEN(MPR_GET_MEM(ejs->result)) != MPR->heap->dead)); return (cp->errorCount > 0) ? EJS_ERR: 0; }