module clox.parserules; import clox.chunk; import clox.compiler; import clox.parser; import clox.scanner; import clox.emitter; import clox.value; import clox.object; alias ParseFn = void function(Compiler* compiler, bool canAssign = false); private void grouping(Compiler* compiler, bool _){ compiler.parser.expression(); compiler.parser.consume(Token.Type.RightParen, "Expect ')' after expression."); } private void unary(Compiler* compiler, bool _){ Token operator = compiler.parser.previous; compiler.parser.parsePrecedence(Precedence.Unary); switch(operator.type){ case Token.Type.Minus: compiler.emitter.emit(OpCode.Negate); break; case Token.Type.Bang: compiler.emitter.emit(OpCode.Not); break; default: assert(0); } } private void binary(Compiler* compiler, bool _){ Token operator = compiler.parser.previous; immutable(ParseRule)* rule = ParseRule.get(operator.type); compiler.parser.parsePrecedence(cast(Precedence)(rule.precedence + 1)); switch(operator.type){ case Token.Type.Plus: compiler.emitter.emit(OpCode.Add); break; case Token.Type.Minus: compiler.emitter.emit(OpCode.Subtract); break; case Token.Type.Star: compiler.emitter.emit(OpCode.Multiply); break; case Token.Type.Slash: compiler.emitter.emit(OpCode.Divide); break; case Token.Type.BangEqual: compiler.emitter.emit(OpCode.NotEqual); break; case Token.Type.EqualEqual: compiler.emitter.emit(OpCode.Equal); break; case Token.Type.Greater: compiler.emitter.emit(OpCode.Greater); break; case Token.Type.GreaterEqual: compiler.emitter.emit(OpCode.GreaterEqual); break; case Token.Type.Less: compiler.emitter.emit(OpCode.Less); break; case Token.Type.LessEqual: compiler.emitter.emit(OpCode.LessEqual); break; default: assert(0); } } private void number(Compiler* compiler, bool _){ import core.stdc.stdlib : strtod; Token token = compiler.parser.previous; double value = strtod(token.lexeme.ptr, null); compiler.emitter.emitConstant(Value.from(value)); } private void literal(Compiler* compiler, bool _){ Token token = compiler.parser.previous; switch(token.type){ case Token.Type.True: compiler.emitter.emit(OpCode.True); break; case Token.Type.False: compiler.emitter.emit(OpCode.False); break; case Token.Type.Nil: compiler.emitter.emit(OpCode.Nil); break; default: assert(0); } } private void strlit(Compiler* compiler, bool _){ Token token = compiler.parser.previous; const char[] str = token.lexeme[1 .. $-1]; Obj.String* strObj = Obj.String.copy(str); compiler.emitter.emitConstant(Value.from(strObj)); } private void variable(Compiler* compiler, bool canAssign){ compiler.parser.namedVariable(compiler.parser.previous, canAssign); } private void and(Compiler* compiler, bool _){ int endJump = compiler.parser.emitJump(OpCode.JumpIfFalse); compiler.emitter.emit(OpCode.Pop); compiler.parser.parsePrecedence(Precedence.And); compiler.parser.patchJump(endJump); } private void or(Compiler* compiler, bool _){ int elseJump = compiler.parser.emitJump(OpCode.JumpIfFalse); int endJump = compiler.parser.emitJump(OpCode.Jump); compiler.parser.patchJump(elseJump); compiler.emitter.emit(OpCode.Pop); compiler.parser.parsePrecedence(Precedence.Or); compiler.parser.patchJump(endJump); } struct ParseRule{ ParseFn prefix; ParseFn infix; Precedence precedence; static immutable(ParseRule)* get(Token.Type type){ return &rules[type]; } } enum Precedence{ None, Assignment, // = Or, // or And, // and Equality, // == != Comparison, // < > <= >= Term, // + - Factor, // * / Unary, // ! - Call, // . () Primary } immutable ParseRule[Token.Type.max+1] rules = [ Token.Type.LeftParen : ParseRule(&grouping, null, Precedence.None), Token.Type.RightParen : ParseRule(null, null, Precedence.None), Token.Type.LeftBrace : ParseRule(null, null, Precedence.None), Token.Type.RightBrace : ParseRule(null, null, Precedence.None), Token.Type.Comma : ParseRule(null, null, Precedence.None), Token.Type.Dot : ParseRule(null, null, Precedence.None), Token.Type.Minus : ParseRule(&unary, &binary, Precedence.Term), Token.Type.Plus : ParseRule(null, &binary, Precedence.Term), Token.Type.Semicolon : ParseRule(null, null, Precedence.None), Token.Type.Slash : ParseRule(null, &binary, Precedence.Factor), Token.Type.Star : ParseRule(null, &binary, Precedence.Factor), Token.Type.Bang : ParseRule(&unary, null, Precedence.None), Token.Type.BangEqual : ParseRule(null, &binary, Precedence.Equality), Token.Type.Equal : ParseRule(null, null, Precedence.None), Token.Type.EqualEqual : ParseRule(null, &binary, Precedence.Equality), Token.Type.Greater : ParseRule(null, &binary, Precedence.Comparison), Token.Type.GreaterEqual : ParseRule(null, &binary, Precedence.Comparison), Token.Type.Less : ParseRule(null, &binary, Precedence.Comparison), Token.Type.LessEqual : ParseRule(null, &binary, Precedence.Comparison), Token.Type.Identifier : ParseRule(&variable, null, Precedence.None), Token.Type.String : ParseRule(&strlit, null, Precedence.None), Token.Type.Number : ParseRule(&number, null, Precedence.None), Token.Type.And : ParseRule(null, &and, Precedence.And), Token.Type.Class : ParseRule(null, null, Precedence.None), Token.Type.Else : ParseRule(null, null, Precedence.None), Token.Type.False : ParseRule(&literal, null, Precedence.None), Token.Type.For : ParseRule(null, null, Precedence.None), Token.Type.Fun : ParseRule(null, null, Precedence.None), Token.Type.If : ParseRule(null, null, Precedence.None), Token.Type.Nil : ParseRule(&literal, null, Precedence.None), Token.Type.Or : ParseRule(null, &or, Precedence.Or), Token.Type.Print : ParseRule(null, null, Precedence.None), Token.Type.Return : ParseRule(null, null, Precedence.None), Token.Type.Super : ParseRule(null, null, Precedence.None), Token.Type.This : ParseRule(null, null, Precedence.None), Token.Type.True : ParseRule(&literal, null, Precedence.None), Token.Type.Var : ParseRule(null, null, Precedence.None), Token.Type.While : ParseRule(null, null, Precedence.None), Token.Type.Error : ParseRule(null, null, Precedence.None), Token.Type.EOF : ParseRule(null, null, Precedence.None), ];