|
|
@@ -48,7 +48,16 @@ typedef struct {
|
|
|
int depth;
|
|
|
} Local;
|
|
|
|
|
|
-typedef struct {
|
|
|
+typedef enum {
|
|
|
+ TYPE_FUNCTION,
|
|
|
+ TYPE_SCRIPT,
|
|
|
+} FunctionType;
|
|
|
+
|
|
|
+typedef struct Compiler {
|
|
|
+ struct Compiler *enclosing;
|
|
|
+ ObjFunction *function;
|
|
|
+ FunctionType type;
|
|
|
+
|
|
|
Local locals[UINT8_COUNT];
|
|
|
int localCount;/// how many locals are in scope
|
|
|
int scopeDepth;
|
|
|
@@ -56,7 +65,6 @@ typedef struct {
|
|
|
|
|
|
Parser parser;
|
|
|
Compiler *current = NULL;
|
|
|
-Chunk *compilingChunk;
|
|
|
|
|
|
static void parsePrecedence(Precedence);
|
|
|
static uint8_t parseVariable(const char *);
|
|
|
@@ -66,12 +74,18 @@ static bool identifiersEqual(Token *a, Token *b);
|
|
|
static ParseRule *getRule(TokenType);
|
|
|
static void statement();
|
|
|
static void declaration();
|
|
|
+static void markInitialized();
|
|
|
+
|
|
|
+static void initCompiler(Compiler *compiler, FunctionType type);
|
|
|
|
|
|
static void beginScope();
|
|
|
static void endScope();
|
|
|
|
|
|
+static void block();
|
|
|
+static ObjFunction *endCompiler();
|
|
|
+
|
|
|
static Chunk *currentChunk() {
|
|
|
- return compilingChunk;
|
|
|
+ return ¤t->function->chunk;
|
|
|
}
|
|
|
|
|
|
static void errorAt(Token *token, const char *message) {
|
|
|
@@ -158,6 +172,38 @@ static uint8_t makeConstant(Value value) {
|
|
|
static void expression() {
|
|
|
parsePrecedence(PREC_ASSIGNMENT);
|
|
|
}
|
|
|
+static void function(FunctionType type) {
|
|
|
+ Compiler compiler;
|
|
|
+ initCompiler(&compiler, type);
|
|
|
+ beginScope();
|
|
|
+
|
|
|
+ consume(TOKEN_LEFT_PAREN, "Expect '(' after function name.");
|
|
|
+
|
|
|
+ ///! Parameters
|
|
|
+ if (!check(TOKEN_RIGHT_PAREN)) {
|
|
|
+ do {
|
|
|
+ current->function->arity++;
|
|
|
+ if (current->function->arity > 255) {
|
|
|
+ errorAtCurrent("Can't have more than 255 parameters.");
|
|
|
+ }
|
|
|
+ uint8_t constant = parseVariable("Expect parameter name.");
|
|
|
+ defineVariable(constant);
|
|
|
+ } while (match(TOKEN_COMMA));
|
|
|
+ }
|
|
|
+ consume(TOKEN_RIGHT_PAREN, "Expect ')' after parameters.");
|
|
|
+ consume(TOKEN_LEFT_BRACE, "Expect '{' before function body.");
|
|
|
+ ///! Body
|
|
|
+ block();
|
|
|
+
|
|
|
+ ObjFunction *fun = endCompiler();
|
|
|
+ emitBytes(OP_CONSTANT, makeConstant(OBJ_VAL(fun)));
|
|
|
+}
|
|
|
+static void funDeclaration() {
|
|
|
+ uint8_t global = parseVariable("Expect function name.");
|
|
|
+ markInitialized();
|
|
|
+ function(TYPE_FUNCTION);
|
|
|
+ defineVariable(global);
|
|
|
+}
|
|
|
/// for example: var a; var b = 10;
|
|
|
static void varDeclaration() {
|
|
|
uint8_t global = parseVariable("Expect variable name.");
|
|
|
@@ -314,7 +360,9 @@ static void synchronize() {
|
|
|
/// | varDecl
|
|
|
/// | statement ;
|
|
|
static void declaration() {
|
|
|
- if (match(TOKEN_VAR)) {
|
|
|
+ if (match(TOKEN_FUN)) {
|
|
|
+ funDeclaration();
|
|
|
+ } else if (match(TOKEN_VAR)) {
|
|
|
varDeclaration();
|
|
|
} else {
|
|
|
statement();
|
|
|
@@ -369,18 +417,35 @@ static void endScope() {
|
|
|
static void emitConstant(Value value) {
|
|
|
emitBytes(OP_CONSTANT, makeConstant(value));
|
|
|
}
|
|
|
-static void initCompiler(Compiler *compiler) {
|
|
|
+static void initCompiler(Compiler *compiler, FunctionType type) {
|
|
|
+ compiler->enclosing = current;// 上一极的 compiler
|
|
|
+ compiler->function = NULL;
|
|
|
+ compiler->type = type;
|
|
|
compiler->localCount = 0;
|
|
|
compiler->scopeDepth = 0;
|
|
|
+ compiler->function = newFunction();
|
|
|
current = compiler;
|
|
|
+ if (type != TYPE_SCRIPT) {
|
|
|
+ ///! Function name
|
|
|
+ current->function->name = copyString(parser.previous.start, parser.previous.length);
|
|
|
+ }
|
|
|
+
|
|
|
+ Local *local = ¤t->locals[current->localCount++];
|
|
|
+ local->depth = 0;
|
|
|
+ local->name.start = "";
|
|
|
+ local->name.length = 0;
|
|
|
}
|
|
|
-static void endCompiler() {
|
|
|
+static ObjFunction *endCompiler() {
|
|
|
emitReturn();
|
|
|
+ ObjFunction *function = current->function;
|
|
|
#ifdef DEBUG_PRINT_CODE
|
|
|
if (!parser.hadError) {
|
|
|
- disassembleChunk(currentChunk(), "code");
|
|
|
+ disassembleChunk(currentChunk(), function->name != NULL ? function->name->chars : "<script>");
|
|
|
}
|
|
|
#endif
|
|
|
+
|
|
|
+ current = current->enclosing;// 当前的 compiler 变成上级 compiler
|
|
|
+ return function;
|
|
|
}
|
|
|
static void grouping(__attribute__((unused)) bool canAssign) {
|
|
|
expression();
|
|
|
@@ -647,11 +712,15 @@ static uint8_t parseVariable(const char *errorMessage) {
|
|
|
|
|
|
return identifierConstant(&parser.previous);
|
|
|
}
|
|
|
+static void markInitialized() {
|
|
|
+ if (current->scopeDepth == 0) return;
|
|
|
+ current->locals[current->localCount - 1].depth = current->scopeDepth;
|
|
|
+}
|
|
|
static void defineVariable(uint8_t global) {
|
|
|
|
|
|
if (current->scopeDepth > 0) {
|
|
|
// markInitialized 未初始化时值 为 -1
|
|
|
- current->locals[current->localCount - 1].depth = current->scopeDepth;
|
|
|
+ markInitialized();
|
|
|
// 本地变量,直接退出
|
|
|
return;
|
|
|
}
|
|
|
@@ -678,11 +747,10 @@ static ParseRule *getRule(TokenType type) {
|
|
|
| statement ;
|
|
|
******************************************************************************
|
|
|
*/
|
|
|
-bool compile(const char *source, Chunk *chunk) {
|
|
|
- Compiler compiler;
|
|
|
+ObjFunction *compile(const char *source) {
|
|
|
initScanner(source);
|
|
|
- initCompiler(&compiler);
|
|
|
- compilingChunk = chunk;
|
|
|
+ Compiler compiler;
|
|
|
+ initCompiler(&compiler, TYPE_SCRIPT);
|
|
|
|
|
|
parser.hadError = false;
|
|
|
parser.panicMode = false;
|
|
|
@@ -693,6 +761,6 @@ bool compile(const char *source, Chunk *chunk) {
|
|
|
declaration();
|
|
|
}
|
|
|
|
|
|
- endCompiler();//! return opcode
|
|
|
- return !parser.hadError;
|
|
|
+ ObjFunction *function = endCompiler();
|
|
|
+ return parser.hadError ? NULL : function;
|
|
|
}
|