private static void ParseFieldList(Lexer.Lexer lexer, out List <Exp> ks, out List <Exp> vs) { ks = null; vs = null; if (lexer.LookAhead() != ETokenType.SepRCurly) { ParseField(lexer, out var k, out var v); ks = new List <Exp> { k }; vs = new List <Exp> { v }; while (IsFieldSep(lexer.LookAhead())) { lexer.NextToken(out _, out _, out _); if (lexer.LookAhead() != ETokenType.SepRCurly) { ParseField(lexer, out k, out v); ks.Add(k); vs.Add(v); } else { break; } } } }
private static Exp ParseExp3(Lexer.Lexer lexer) { var exp = ParseExp2(lexer); while (true) { switch (lexer.LookAhead()) { case ETokenType.OpMul: case ETokenType.OpMod: case ETokenType.OpDiv: case ETokenType.OpIDiv: { lexer.NextToken(out var line, out var op, out _); var arith = new BinopExp { Line = line, Op = op, Exp1 = exp, Exp2 = ParseExp2(lexer) }; exp = OptimizeArithBinaryOp(arith); break; } default: return(exp); } } }
private static Exp ParseExp5(Lexer.Lexer lexer) { var exp = ParseExp4(lexer); if (lexer.LookAhead() != ETokenType.OpConcat) { return(exp); } var line = 0; var exps = new List <Exp> { exp }; while (lexer.LookAhead() == ETokenType.OpConcat) { lexer.NextToken(out line, out _, out _); exps.Add(ParseExp4(lexer)); } return(new ConcatExp { Line = line, Exps = exps }); }
private static Exp ParseExp6(Lexer.Lexer lexer) { var exp = ParseExp5(lexer); while (true) { switch (lexer.LookAhead()) { case ETokenType.OpShl: case ETokenType.OpShr: { lexer.NextToken(out var line, out var op, out _); var shx = new BinopExp { Line = line, Op = op, Exp1 = exp, Exp2 = ParseExp5(lexer) }; exp = OptimizeBitwiseBinaryOp(shx); break; } default: return(exp); } } }
private static void ParseField(Lexer.Lexer lexer, out Exp k, out Exp v) { k = null; v = null; if (lexer.LookAhead() == ETokenType.SepLBracket) { lexer.NextToken(out _, out _, out _); k = ParseExp(lexer); lexer.NextTokenOfKind(ETokenType.SepRBracket, out _, out _); lexer.NextTokenOfKind(ETokenType.OpAssign, out _, out _); v = ParseExp(lexer); return; } var exp = ParseExp(lexer); if (exp is NameExp nameExp) { if (lexer.LookAhead() == ETokenType.OpAssign) { lexer.NextToken(out _, out _, out _); k = new StringExp { Line = nameExp.Line, Str = nameExp.Name }; v = ParseExp(lexer); return; } } v = exp; }
private Program TestParseProgram(string input) { var l = new Lexer.Lexer(input); var p = new Parser.Parser(l); return(p.ParseProgram()); }
private static List<Exp> ParseRetExps(Lexer.Lexer lexer) { if (lexer.LookAhead() != ETokenType.KwReturn) return null; lexer.NextToken(out _, out _, out _); var ret = new List<Exp>(); switch (lexer.LookAhead()) { case ETokenType.Eof: case ETokenType.KwEnd: case ETokenType.KwElse: case ETokenType.KwElseIf: case ETokenType.KwUntil: return ret; case ETokenType.SepSemi: lexer.NextToken(out _, out _, out _); return ret; default: var exps = ParseExpList(lexer); if (lexer.LookAhead() == ETokenType.SepSemi) lexer.NextToken(out _, out _, out _); return exps; } }
public void TestBooleanExpression() { var tests = new Dictionary <string, bool> { { "true;", true }, { "false;", false } }; foreach (var tt in tests) { var l = new Lexer.Lexer(tt.Key); var p = new Parser(l); var program = p.ParseProgram(); CheckParserErrors(p); Assert.AreEqual(1, program.Statements.Count, $"program has not enough statements. got={program.Statements.Count}"); var stmt = program.Statements[0] as ExpressionStatement; Assert.IsNotNull(stmt, $"program.Statement[0] is not IntegerLiteral. got={program.Statements[0].GetType().Name}"); Assert.IsNotNull(stmt.Expression, "stmt.Expression is null"); var ident = stmt.Expression as Boolean; Assert.IsNotNull(ident, $"exp is not Boolean. got={stmt.Expression.GetType().Name}"); Assert.AreEqual(tt.Value, ident.Value, $"ident.Value not {tt.Value}. got={ident.Value}"); Assert.AreEqual(tt.Value.ToString().ToLower(), ident.TokenLiteral, $"ident.TokenLiteral not {tt.Value.ToString().ToLower()}. got={ident.TokenLiteral}"); } }
public void TestCallExpressionParsing() { const string input = "add(1, 2 * 3, 4 + 5);"; var l = new Lexer.Lexer(input); var p = new Parser(l); var program = p.ParseProgram(); CheckParserErrors(p); Assert.AreEqual(1, program.Statements.Count, $"program.Statements does not contain 1 statement. got={program.Statements.Count}"); var stmt = program.Statements[0] as ExpressionStatement; Assert.IsNotNull(stmt, $"stmt is not ast.ExpressionStatement. got={program.Statements[0].GetType().Name}"); var exp = stmt.Expression as CallExpression; Assert.IsNotNull(exp, $"stmt.Expression is not ast.CallExpression. got={stmt.Expression.GetType().Name}"); TestIdentifier(exp.Function, "add"); Assert.AreEqual(3, exp.Arguments.Count, $"wrong length of arguments. got={exp.Arguments.Count}"); TestLiteralExpression(exp.Arguments[0], 1); TestInfixExpression(exp.Arguments[1], 2, "*", 3); TestInfixExpression(exp.Arguments[2], 4, "+", 5); }
public void TestIfExpression() { const string input = "if (x < y) { x }"; var l = new Lexer.Lexer(input); var p = new Parser(l); var program = p.ParseProgram(); CheckParserErrors(p); Assert.AreEqual(1, program.Statements.Count, $"program.Body does not contain 1 statement. got={program.Statements.Count}"); var stmt = program.Statements[0] as ExpressionStatement; Assert.IsNotNull(stmt, $"program.Statements[0] is not ast.ExpressionStatement. got={program.Statements[0].GetType().Name}"); var exp = stmt.Expression as IfExpression; Assert.IsNotNull(exp, $"stmt.Expression is not ast.IfExpression. got={stmt.Expression.GetType().Name}"); TestInfixExpression(exp.Condition, "x", "<", "y"); Assert.AreEqual(1, exp.Consequence.Statements.Count, $"consequence is not 1 statement. got={exp.Consequence.Statements.Count}"); var consequence = exp.Consequence.Statements[0] as ExpressionStatement; Assert.IsNotNull(consequence, $"Statements[0] is not ast.ExpressionStatement. got={exp.Consequence.Statements[0].GetType().Name}"); TestIdentifier(consequence.Expression, "x"); Assert.IsNull(exp.Alternative, $"exp.Alternative.Statements was not nil. got={exp.Alternative}"); }
private static Exp ParseExp10(Lexer.Lexer lexer) { var exp = ParseExp9(lexer); while (true) { switch (lexer.LookAhead()) { case ETokenType.OpLt: case ETokenType.OpGt: case ETokenType.OpNe: case ETokenType.OpLe: case ETokenType.OpGe: case ETokenType.OpEq: { lexer.NextToken(out var line, out var op, out _); exp = new BinopExp { Line = line, Op = op, Exp1 = exp, Exp2 = ParseExp9(lexer) }; break; } default: return(exp); } } }
public void TestReturnStatements() { var tests = new Dictionary <string, object> { { "return 5;", 5 }, { "return true;", true }, { "return foobar;", "foobar" } }; foreach (var tt in tests) { var l = new Lexer.Lexer(tt.Key); var p = new Parser(l); var program = p.ParseProgram(); CheckParserErrors(p); Assert.AreEqual(1, program.Statements.Count, $"program.Statements does not contain 1 statement. got={program.Statements.Count}"); var stmt = program.Statements[0]; var returnStmt = stmt as ReturnStatement; Assert.IsNotNull(returnStmt, $"stmt not ReturnStatement. got={stmt.GetType().Name}"); Assert.AreEqual("return", returnStmt.TokenLiteral, $"returnStmt.TokenLiteral not 'return', got {returnStmt.TokenLiteral}"); TestLiteralExpression(returnStmt.ReturnValue, tt.Value); } }
public void TestMacroLiteralParsing() { const string input = "macro(x, y) { x + y; }"; var l = new Lexer.Lexer(input); var p = new Parser(l); var program = p.ParseProgram(); CheckParserErrors(p); Assert.AreEqual(1, program.Statements.Count, $"program.Statements does not contain 1 statement. got={program.Statements.Count}"); var stmt = program.Statements[0] as ExpressionStatement; Assert.IsNotNull(stmt, $"program.Statements[0] is not ast.ExpressionStatement. got={program.Statements[0].GetType().Name}"); var macro = stmt.Expression as MacroLiteral; Assert.IsNotNull(macro, $"stmt.Expression is not ast.MacroLiteral. got={stmt.Expression.GetType().Name}"); Assert.AreEqual(2, macro.Parameters.Count, $"macro literal parameters wrong. want 2, got={macro.Parameters.Count}"); TestLiteralExpression(macro.Parameters[0], "x"); TestLiteralExpression(macro.Parameters[1], "y"); Assert.AreEqual(1, macro.Body.Statements.Count, $"macro.Body.Statements has not 1 statement. got={macro.Body.Statements.Count}"); var bodyStmt = macro.Body.Statements[0] as ExpressionStatement; Assert.IsNotNull(bodyStmt, $"macro body stmt is not ast.ExpressionStatement. got={macro.Body.Statements[0].GetType().Name}"); TestInfixExpression(bodyStmt.Expression, "x", "+", "y"); }
public void TestParsingHashLiteralsWithExpressions() { const string input = "{\"one\": 0 + 1, \"two\": 10 - 8, \"three\": 15 / 5}"; var l = new Lexer.Lexer(input); var p = new Parser(l); var program = p.ParseProgram(); CheckParserErrors(p); var stmt = program.Statements[0] as ExpressionStatement; var hash = stmt.Expression as HashLiteral; Assert.IsNotNull(hash, $"exp is not HashLiteral. got={stmt.Expression.GetType().Name}"); Assert.AreEqual(3, hash.Pairs.Count, $"hash.Pairs has wrong length. got={hash.Pairs.Count}"); var tests = new Dictionary <string, Action <IExpression> > { { "one", e => TestInfixExpression(e, 0, "+", 1) }, { "two", e => TestInfixExpression(e, 10, "-", 8) }, { "three", e => TestInfixExpression(e, 15, "/", 5) }, }; foreach (var pair in hash.Pairs) { var literal = pair.Key as StringLiteral; Assert.IsNotNull(literal, $"key is not ast.StringLiteral. got={pair.Key.GetType().Name}"); Assert.IsTrue(tests.ContainsKey(literal.ToString())); var testFunc = tests[literal.ToString()]; testFunc(pair.Value); } }
private static Stat ParseBreakStat(Lexer.Lexer lexer) { lexer.NextTokenOfKind(ETokenType.KwBreak, out _, out _); return(new BreakStat { Line = lexer.Line }); }
public void TestMethod3() { Lexer.Lexer lexer = new Lexer.Lexer(); lexer.AddDefinition(new TokenDefinition { Regex = new Regex("[Aa][Dd][Dd]"), Type = TokenTyp.Add }); lexer.AddDefinition(new TokenDefinition { Regex = new Regex("\\("), Type = TokenTyp.OpenParenthesis }); lexer.AddDefinition(new TokenDefinition { Regex = new Regex("\\)"), Type = TokenTyp.CloseParenthesis }); lexer.AddDefinition(new TokenDefinition { Regex = new Regex(","), Type = TokenTyp.Comma }); lexer.AddDefinition(new TokenDefinition { Regex = new Regex(@"\d+"), Type = TokenTyp.Number }); lexer.AddDefinition(new TokenDefinition { Regex = new Regex(@"\s+"), Type = TokenTyp.Whitespace, IsIgnored = true }); LanguageParser parser = new LanguageParser(); int res = parser.Parse(lexer.Tokenize("ADD(ADD(1,ADD(1,3)) ,ADD(1,5)").ToList()); Assert.AreEqual(res, 11); }
private static Stat ParseIfStat(Lexer.Lexer lexer) { var exps = new List <Exp>(); var blocks = new List <Block>(); lexer.NextTokenOfKind(ETokenType.KwIf, out _, out _); exps.Add(ParseExp(lexer)); lexer.NextTokenOfKind(ETokenType.KwThen, out _, out _); blocks.Add(ParseBlock(lexer)); while (lexer.LookAhead() == ETokenType.KwElseIf) { lexer.NextToken(out _, out _, out _); exps.Add(ParseExp(lexer)); lexer.NextTokenOfKind(ETokenType.KwThen, out _, out _); blocks.Add(ParseBlock(lexer)); } if (lexer.LookAhead() == ETokenType.KwElse) { lexer.NextToken(out _, out _, out _); exps.Add(new TrueExp { Line = lexer.Line }); blocks.Add(ParseBlock(lexer)); } lexer.NextTokenOfKind(ETokenType.KwEnd, out _, out _); return(new IfStat { Exps = exps, Blocks = blocks }); }
public void SetTextAsThisToken(string rawText) { //Stream stream = new MemoryStream(UnicodeEncoding.UTF8.GetBytes(rawText)); StreamReader stream = new StreamReader(new MemoryStream(Globals.LpcInternalCodec.GetBytes(rawText)), Globals.LpcFileCodec, false); ParseMap map; SyntaxRules lpcRules = new SyntaxRules(out map); Scanner.Scanner scanner = new Scanner.Scanner(stream); Lexer.Lexer lexer = new Lexer.Lexer(scanner); Parser parser = new Parser(lexer, map); foreach (Token token in parser.LPCTokens) { if (token.Lexmes.Count > 0) { Token copy = token; Type = copy.Type; object tempLexmes = copy.Lexmes.ToArray().Clone(); this.Lexmes = new List <Stellarmass.LPC.Lexer.Lexme>((Lexer.Lexme[])tempLexmes); for (int outter = 0; outter < copy.Children.Count; outter++) { this.Children.Add(new List <Token>()); foreach (Token t in copy.Children[outter]) { this.Children[outter].Add(new Token(t)); } } return; } } return; }
public Engine(Lexer.Lexer lexer, MetadataHost host) { mLexer = lexer; Host = host; InitializeKeywords(); Move(); }
public void Start(TextReader reader, TextWriter writer) { var env = new Environment(); var macroEnv = new Environment(); while (true) { writer.Write(Prompt); var line = reader.ReadLine(); if (string.IsNullOrEmpty(line)) { return; } var l = new Lexer.Lexer(line); var p = new Parser.Parser(l); var program = p.ParseProgram(); if (p.Errors.Any()) { PrintParserErrors(writer, p.Errors); continue; } var evaluator = new Evaluator.Evaluator(); evaluator.DefineMacros(program, macroEnv); var expanded = evaluator.ExpandMacros(program, macroEnv); var evaluated = evaluator.Eval(expanded, env); if (evaluated != null) { writer.WriteLine(evaluated.Inspect()); } } }
public void TestExpressionFunctionReturnTypeBinding() { const string src = "namespace MyNamespace" + "{" + " class MyClass" + " {" + " func Add(int a, int b) -> return new MyClass2()" + " }" + "" + " class MyClass2" + " {" + " " + " }" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); var binder = new Binder(); var semanticModel = binder.Bind(new List<CompilationUnitSyntax> { ast }).Single(); var boundNamespace = semanticModel.Namespaces.Single(x => x.Name == "MyNamespace"); var expectedFunctionReturnType = boundNamespace.Types.Single(x => x.Name == "MyClass2"); var function = boundNamespace.Types.Single(x => x.Name == "MyClass").Functions.Single(x => x.Name == "Add"); Assert.AreSame(expectedFunctionReturnType, function.ReturnType); }
public void TestParsingHashLiteralsIntegerKeys() { const string input = "{1: 1, 2: 2, 3: 3}"; var l = new Lexer.Lexer(input); var p = new Parser(l); var program = p.ParseProgram(); CheckParserErrors(p); var stmt = program.Statements[0] as ExpressionStatement; var hash = stmt.Expression as HashLiteral; Assert.IsNotNull(hash, $"exp is not HashLiteral. got={stmt.Expression.GetType().Name}"); var expected = new Dictionary <string, long> { { "1", 1 }, { "2", 2 }, { "3", 3 } }; foreach (var pair in hash.Pairs) { var literal = pair.Key as IntegerLiteral; Assert.IsNotNull(literal, $"key is not ast.IntegerLiteral. got={pair.Key.GetType().Name}"); var expectedValue = expected[literal.ToString()]; TestIntegerLiteral(pair.Value, expectedValue); } }
public Parser(Lexer.Lexer lexer) { this.lexer = lexer; this.errors = new List <string>(); this.nextToken(); this.nextToken(); }
private static Stat ParseGotoStat(Lexer.Lexer lexer) { lexer.NextTokenOfKind(ETokenType.KwGoto, out _, out _); lexer.NextIdentifier(out _, out var name); return(new GotoStat { Name = name }); }
public static Block Parse(string chunk, string chunkName) { var lexer = new Lexer.Lexer(chunk, chunkName); var block = ParseBlock(lexer); lexer.NextTokenOfKind(ETokenType.Eof, out _, out _); return(block); }
private static Stat ParseLabelStat(Lexer.Lexer lexer) { lexer.NextTokenOfKind(ETokenType.SepLabel, out _, out _); lexer.NextIdentifier(out _, out var name); lexer.NextTokenOfKind(ETokenType.SepLabel, out _, out _); return(new LabelStat { Name = name }); }
private IObject TestEval(string input) { var l = new Lexer.Lexer(input); var p = new Parser.Parser(l); var program = p.ParseProgram(); var env = new Environment(); return(new Evaluator().Eval(program, env)); }
private static Block ParseBlock(Lexer.Lexer lexer) { return new Block { Stats = ParseStats(lexer), RetExps = ParseRetExps(lexer), LastLine = lexer.Line }; }
private static Stat ParseDoStat(Lexer.Lexer lexer) { lexer.NextTokenOfKind(ETokenType.KwDo, out _, out _); var block = ParseBlock(lexer); lexer.NextTokenOfKind(ETokenType.KwEnd, out _, out _); return(new DoStat { Block = block }); }
public Parser(Lexer.Lexer input, int lookaheadCount) { this.input = input; this.lookaheadCount = lookaheadCount; lookahead = new Token[lookaheadCount]; for (int i = 1; i <= lookaheadCount; i++) { ConsumeNextToken(); } }
private static Exp ParseNumberExp(Lexer.Lexer lexer) { lexer.NextToken(out var line, out _, out var token); var numberStyle = NumberStyles.Number; var e = 1.0; if (token.StartsWith("0x")) { token = token.Substring(2); if (token.Contains("p")) { var eIdx = token.IndexOf("p"); var t = LuaFloat.Parse("1" + token.Substring(eIdx).Replace("p", "e")); var d = t > 1 ? 0.1 : 10; while (t != 1) { e *= d > 1 ? 0.5 : 2; t *= d; } token = token.Substring(0, eIdx); } numberStyle = NumberStyles.HexNumber; } if (LuaInt.TryParse(token, numberStyle, new NumberFormatInfo(), out var result)) { if (e != 1.0) { return new FloatExp { Line = line, Val = result * e } } ; return(new IntegerExp { Line = line, Val = result }); } if (LuaFloat.TryParse(token, out var fResult)) { return new FloatExp { Line = line, Val = fResult } } ; Debug.Panic("not a number: " + token); return(null); } } }
/// <summary> /// コンパイルするコードを指定してコンパイルし、実行します。 /// </summary> /// <param name="code">コンパイルされるコード文字列。</param> /// <returns>コンパイルに成功したとき true、それ以外のとき false。</returns> public LuryObject Evaluate(string code) { var lexer = new Lexer.Lexer(code + '\n'); var succeedTokenize = lexer.Tokenize(); lexer.Logger.CopyTo(this.OutputLogger); if (!succeedTokenize) { return(null); } var globalContext = new LuryContext(); Intrinsic.SetBuiltInFunctions(globalContext); var parser = new Parser(); Routine routine = null; // parsing try { routine = (Routine)parser.yyparse(new Lex2yyInput(lexer), new yydebug.yyDebugSimple()); } catch (yyParser.yyException ex) { this.ReportyyException(ex, code); return(null); } // running if (routine == null) { return(null); } else { try { var exit = routine.Evaluate(globalContext); if (exit.ExitReason == StatementExitReason.Break) { throw new LuryException(LuryExceptionType.WrongBreak); } return(exit.ReturnValue); } catch (LuryException ex) { Console.Error.WriteLine(ex.Message); return(null); } } }
public void TestClass() { var lexer = new Lexer.Lexer(); var tokens = lexer.Lex( string.Format(NamespaceSource, string.Format(ClassSource, string.Empty, string.Empty, string.Empty))); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); Assert.IsInstanceOf<CompilationUnitSyntax>(ast); Assert.IsNotEmpty(ast.Namespaces); Assert.IsNotEmpty(ast.Namespaces[0].Classes); Assert.AreEqual("ClassSample", ast.Namespaces[0].Classes[0].Name.Value); Assert.AreEqual("DSampleProtocol", ast.Namespaces[0].Classes[0].ProtocolName.Value); }
public void TestExpressionFunction() { const string functionSource = "func FunctionSample(int a, int b, int c) -> return a * b * c"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex( string.Format( NamespaceSource, string.Format(ClassSource, functionSource, string.Empty, string.Empty))); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); Assert.IsNotEmpty(ast.Namespaces[0].Classes[0].Functions); Assert.IsInstanceOf<FunctionSyntax>(ast.Namespaces[0].Classes[0].Functions[0]); Assert.AreEqual("FunctionSample", ast.Namespaces[0].Classes[0].Functions[0].Name.Value); }
public void TestFieldTypeToVariableBinding() { const string src = "namespace MyNamespace" + "{" + " class MyClass" + " {" + " var field : false" + " var field2 : new MyClass2()" + " func MyFunc()" + " {" + " var i : field" + " var i2 : field2" + " }" + " }" + "" + " class MyClass2" + " {" + " " + " }" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); var binder = new Binder(); var semanticModel = binder.Bind(new List<CompilationUnitSyntax> { ast }).Single(); var boundNamespace = semanticModel.Namespaces.Single(x => x.Name == "MyNamespace"); var referencedBoundType = boundNamespace.Types.Single(x => x.Name == "MyClass2"); var boundType = boundNamespace.Types.Single(x => x.Name == "MyClass"); var boundFunction = (BoundFunction)boundType.Functions.Single(x => x.Name == "MyFunc"); Assert.IsInstanceOf<BoolCompilerGeneratedType>( ((IBoundMember)((BoundScopeStatement)boundFunction.Statements).Statements[0]).Type); Assert.AreSame( ((IBoundMember)((BoundScopeStatement)boundFunction.Statements).Statements[1]).Type, referencedBoundType); }
public void Test_GenericConstraints(string constraint) { const string template = "class SomeGenericClass!(T) where T {0}"; var parserFunc = new Action<string>( opSrc => { var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(string.Format(template, opSrc)); var parser = new Parser.Parser(tokens); parser.Parse(); }); Assert.That(() => parserFunc(constraint), Throws.Nothing); }
public void Test_GenericLocalFunction_Call() { const string src = "namespace MyNamespace" + "{" + " func GenericFunction!(TypeA, TypeB)(TypeA a, TypeB b)" + " {" + " let anonFunc : func!(TypeX, TypeY)(TypeX x, TypeY y) -> return x" + " anonFunc!(a, a)" + " }" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); Assert.DoesNotThrow(() => parser.Parse()); }
public void Test_InvalidOperatorNames_Throw() { const string template = "namespace MyNamespace" + "{{" + " class MyClass2" + " {{" + " {0}" + " }}" + "}}"; var parserFunc = new Action<string>( opSrc => { var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(string.Format(template, opSrc)); var parser = new Parser.Parser(tokens); parser.Parse(); }); Assert.That(() => parserFunc("operator Addd(MyClassName opA, MyClassName opB) -> return true"), Throws.InstanceOf<KiwiSyntaxException>().With.Message.EqualTo("Invalid operator function name 'Addd'")); }
public void Test_primary_Constructor() { const string code = @"namespace MyNamespace" + "{" + " class MyClass" + " {" + " primary Constructor(int val)" + " {" + " }" + " }" + "}"; var parserFunc = new Action<string>( opSrc => { var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(opSrc); var parser = new Parser.Parser(tokens); parser.Parse(); }); Assert.That(() => parserFunc(code), Throws.Nothing); }
public void Test_IsExpression_ThrowsTypeNotDefined() { const string src = "namespace MyNamespace" + "{" + " class MyClass" + " {" + " func Add(int a, int b) -> return a * b" + " }" + "" + " class MyClass2" + " {" + " var myClassField : new MyClass()" + " func Foo() -> bool" + " {" + " return myClassField is MyClassS" + " }" + " }" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); var binder = new Binder(); Assert.That( () => binder.Bind(new List<CompilationUnitSyntax>() { ast }), Throws.InstanceOf<KiwiSemanticException>().With.Message.EqualTo("MyClassS undefined Type")); }
public void Test_IsExpression() { const string src = "namespace MyNamespace" + "{" + " class MyClass" + " {" + " func Add(int a, int b) -> return a * b" + " }" + "" + " class MyClass2" + " {" + " var myClassField : new MyClass()" + " func Foo() -> bool" + " {" + " return myClassField is MyClass" + " }" + " }" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); var binder = new Binder(); var boundCompilationUnit = binder.Bind(new List<CompilationUnitSyntax>() { ast }).Single(); var type = boundCompilationUnit.Namespaces[0].Types.Single(x => x.Name == "MyClass"); var function = (BoundFunction) boundCompilationUnit.Namespaces[0].Types.Single(x => x.Name == "MyClass2") .Functions.Single(x => x.Name == "Foo"); var returnStatement = (BoundReturnStatement)((BoundScopeStatement)function.Statements).Statements[0]; var boundBinaryExpression = (BoundBinaryExpression)returnStatement.Expression; Assert.AreEqual(BinaryOperators.Is, boundBinaryExpression.Operator); Assert.IsInstanceOf<BoundTypeExpression>(boundBinaryExpression.Right); Assert.AreSame(((BoundTypeExpression)boundBinaryExpression.Right).ReferencedType, type); }
public void Test_InfixCall_Types() { const string src = "namespace MyNamespace" + "{" + " class MyClass2" + " {" + " infix func Add(int a, int b) -> return a + b" + " func Foo()" + " {" + " var a : 1 Add 2" + " }" + " }" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); var binder = new Binder(); var boundCompilationUnits = binder.Bind(new List<CompilationUnitSyntax>() { ast }); var myClass2Type = boundCompilationUnits[0].Namespaces[0].Types.Single(); var fooFunction = myClass2Type.Functions.Single(x => x.Name == "Foo"); var addFunction = myClass2Type.Functions.Single(x => x.Name == "Add"); Assert.IsInstanceOf<BoundFunction>(addFunction); Assert.IsTrue(((BoundFunction)addFunction).IsInfixFunction); Assert.IsInstanceOf<BoundFunction>(fooFunction); var boundFunction = (BoundFunction)fooFunction; Assert.IsInstanceOf<BoundScopeStatement>(boundFunction.Statements); var boundScopeStatement = (BoundScopeStatement)boundFunction.Statements; Assert.IsInstanceOf<BoundVariableDeclarationStatement>(boundScopeStatement.Statements[0]); var boundVariableDeclarationStatement = (BoundVariableDeclarationStatement)boundScopeStatement.Statements[0]; Assert.IsInstanceOf<BoundInvocationExpression>(boundVariableDeclarationStatement.BoundExpression); var boundInvocationExpression = (BoundInvocationExpression)boundVariableDeclarationStatement.BoundExpression; Assert.IsInstanceOf<BoundMemberExpression>(boundInvocationExpression.ToInvoke); var boundMemberExpression = (BoundMemberExpression)boundInvocationExpression.ToInvoke; Assert.AreSame(addFunction, boundMemberExpression.BoundMember); }
public void Test_IfStatement_IfConditionMustBeBool() { const string src = "namespace MyNamespace" + "{" + " class MyClass" + " {" + " func Add(int a, int b) " + " { " + " if(a)" + " {" + " " + " }" + " }" + " }" + "" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); var binder = new Binder(); Assert.That( () => binder.Bind(new List<CompilationUnitSyntax>() { ast }), Throws.InstanceOf<KiwiSemanticException>().With.Message.EqualTo("If condition must be of Type Bool")); }
public void Test_TryCatch() { const string src = "namespace MyNamespace" + "{" + " class GenericClass(TypeA, TypeB)" + " {" + " Constructor(TypeA arg1, TypeB arg2)" + " {" + " Try" + " {" + " }" + " catch(Error)" + " {" + " }" + " }" + " }" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); Assert.DoesNotThrow(() => parser.Parse()); }
public void Test_ValidOperatorNames_DontThrow(string opCode) { const string template = "namespace MyNamespace" + "{{" + " class MyClass2" + " {{" + " {0}" + " }}" + "}}"; var parserFunc = new Action<string>( opSrc => { var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(string.Format(template, opSrc)); var parser = new Parser.Parser(tokens); parser.Parse(); }); Assert.That(() => parserFunc(opCode), Throws.Nothing); }
public void Test_VariableWithSameName_Throws() { const string src = "namespace MyNamespace" + "{" + " class MyClass" + " {" + " func Add(int a, int b)" + " {" + " var a : 1" + " var b : 2" + " var a : 1" + " }" + " }" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); var binder = new Binder(); Assert.That( () => binder.Bind(new List<CompilationUnitSyntax> { ast }), Throws.TypeOf<KiwiSemanticException>().With.Message.EqualTo("a already defined.")); }
public void Test_ArrayAccessInvalidParameter_Throws() { const string src = "namespace MyNamespace" + "{" + " class MyClass" + " {" + " func Add(int a, int b)" + " { " + " var c : new int[1][1]" + " var d : c[1]" + " }" + " }" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); var binder = new Binder(); Assert.That( () => binder.Bind(new List<CompilationUnitSyntax>() { ast }), Throws.InstanceOf<KiwiSemanticException>() .With.Message.EqualTo("Parameter count (1) must match array dimension count (2)")); }
public void Test_MemberAccessExpressionBinding() { const string src = "namespace MyNamespace" + "{" + " class MyClass" + " {" + " func Add(int a, int b) -> return a * b" + " }" + "" + " class MyClass2" + " {" + " var addMethod : new MyClass().Add" + " }" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); var binder = new Binder(); var boundCompilationUnit = binder.Bind(new List<CompilationUnitSyntax>() { ast }).Single(); var function = boundCompilationUnit.Namespaces[0].Types.Single(x => x.Name == "MyClass") .Functions.Single(x => x.Name == "Add"); var field = boundCompilationUnit.Namespaces[0].Types.Single(x => x.Name == "MyClass2") .Fields.Single(x => x.Name == "addMethod"); Assert.That( () => field.Type, Is.InstanceOf<FunctionCompilerGeneratedType>() .And.Property("ReturnType") .InstanceOf<IntCompilerGeneratedType>()); CollectionAssert.AllItemsAreInstancesOfType( ((FunctionCompilerGeneratedType)field.Type).ParameterTypes, typeof(IntCompilerGeneratedType)); }
public void Test_Optional() { const string src = "namespace MyNamespace" + "{" + " class Class" + " {" + " Constructor(Optional!(int) i, Optional!(string) s)" + " {" + " }" + " }" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); Assert.DoesNotThrow(() => parser.Parse()); }
public void Test_ObjectCreationExpression_ThrowsNoConstructorWithoutArguments() { const string src = "namespace MyNamespace" + "{" + " class MyClass" + " {" + " Constructor(int a){}" + " }" + " class MyClass2" + " {" + " func Foo()" + " {" + " var a : new MyClass()" + " }" + " }" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); var binder = new Binder(); Assert.That( () => binder.Bind(new List<CompilationUnitSyntax>() { ast }), Throws.InstanceOf<KiwiSemanticException>() .With.Message.EqualTo("MyNamespace.MyClass has no constructor without arguments.")); }
public void Test_Infix_NamespaceLevel() { const string src = "namespace MyNamespace" + "{" + " infix func Add(int a, int b) -> return a + b" + " class MyClass2" + " {" + " func Foo()" + " {" + " var a : 1 Add 2" + " }" + " }" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); var namespaceSyntax = ast.Namespaces.Single(x => x.Name.Value == "MyNamespace"); var infixFunction = namespaceSyntax.Functions.Single(x=>x.Name.Value == "Add"); Assert.IsInstanceOf<InfixFunctionSyntax>(infixFunction); }
public void Test_Operator_FunctionMapping() { const string src = "namespace MyNamespace" + "{" + " class MyClass2" + " {" + " operator Add(MyClass2 opA, MyClass2 opB) -> return new MyClass2()" + " operator Sub(MyClass2 opA, MyClass2 opB) -> return new MyClass2()" + " operator Mult(MyClass2 opA, MyClass2 opB) -> return new MyClass2()" + " operator Div(MyClass2 opA, MyClass2 opB) -> return new MyClass2()" + " operator Pow(MyClass2 opA, MyClass2 opB) -> return new MyClass2()" + " operator Range(MyClass2 opA, MyClass2 opB) -> return new MyClass2[1]" + " operator In(MyClass2 opA, MyClass2 opB) -> return true" + " }" + " " + " class TestClass" + " {" + " func TestBinaryFunc()" + " {" + " var instance : new MyClass2()" + " var testAdd : instance + new MyClass2()" + " var testSub : instance - new MyClass2()" + " var testMult : instance * new MyClass2()" + " var testDiv : instance / new MyClass2()" + " var testPow : instance ^ new MyClass2()" + " var testRange : instance..newMyClass2()" + " var testIn : instance in new myClass2[10]" + " }" + "" + "" + " func TestAssignFunc()" + " {" + " var instance : None MyClass2" + " instance +: new MyClass2()" + " instance -: new MyClass2()" + " instance *: new MyClass2()" + " instance ^: new MyClass2()" + " instance /: new MyClass2()" + " }" + " }" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); var binder = new Binder(); var boundCompilationUnit = binder.Bind(new List<CompilationUnitSyntax>() { ast }).Single(); var boundNamespace = boundCompilationUnit.Namespaces.Single(x=>x.Name== "MyNamespace"); var operatorClass = boundNamespace.Types.Single(x=>x.Name== "MyClass2"); var testClass = boundNamespace.Types.Single(x=>x.Name == "TestClass"); var testBinaryFunc = testClass.Functions.Single(x=>x.Name== "TestBinaryFunc"); var testAssignFunc = testClass.Functions.Single(x=>x.Name== "TestAssignFunc"); }
public void Test_GenericFunction_NamespaceLevel() { const string src = "namespace MyNamespace" + "{" + " func GenericFunction!(TypeA, TypeB)(TypeA a, TypeB b)" + " {" + " }" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); Assert.DoesNotThrow(() => parser.Parse()); }
public void Test_RecursivExpressionFunction_DoesThrow() { const string src = "namespace MyNamespace" + "{" + " class MyClass" + " {" + " func Add(int a, int b) -> return Add(1, 2)" + " }" + "" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); var binder = new Binder(); Assert.That( () => binder.Bind(new List<CompilationUnitSyntax>() { ast }), Throws.InstanceOf<KiwiSemanticException>().With.Message.EqualTo("Add Type cannot be inferred")); }
public void Test_GenericClass() { const string src = "namespace MyNamespace" + "{" + " class GenericClass(TypeA, TypeB)" + " {" + " var mutable1 : None TypeA;" + " var mutable2 : None TypeB;" + " Constructor(TypeA arg1, TypeB arg2)" + " {" + " mutable1 : arg1;" + " mutable2 : arg2;" + " }" + " }" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); Assert.DoesNotThrow(() => parser.Parse()); }
public void Test_Scope_VariableNotDefined() { const string src = "namespace MyNamespace" + "{" + " class MyClass" + " {" + " func Add(int a, int b) " + " { " + " {" + " var i : 1337 + b" + " }" + " var c : a * b * i" + " }" + " }" + "" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); var binder = new Binder(); Assert.That( () => binder.Bind(new List<CompilationUnitSyntax>() { ast }), Throws.InstanceOf<KiwiSemanticException>().With.Message.EqualTo("i not defined")); }
public void Test_Function_VisibilityModifiers(string code) { const string template = "namespace MyNamespace" + "{{" + " class MyClass" + " {{" + " {0}" + " }}" + "}}"; var parserFunc = new Action<string>( opSrc => { var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(string.Format(template, opSrc)); var parser = new Parser.Parser(tokens); parser.Parse(); }); Assert.That(() => parserFunc(code), Throws.Nothing); }
public void Test_SwitchStatement_CasesTypeMustMatchSwitchConditionType() { const string src = "namespace MyNamespace" + "{" + " class MyClass" + " {" + " func Add(int a, int b) " + " { " + " switch(a)" + " {" + " case \"LOL\" -> Add(1, 0)" + " }" + " }" + " }" + "" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); var binder = new Binder(); Assert.That( () => binder.Bind(new List<CompilationUnitSyntax>() { ast }), Throws.InstanceOf<KiwiSemanticException>() .With.Message.EqualTo("Switch cases condition type must match switch condition type")); }
public void Test_IfElseExpression_IfTrueIfFalseTypeMustBeEqual() { const string src = "namespace MyNamespace" + "{" + " class MyClass" + " {" + " func Add(int a, float b) -> return if(true) a else b" + " }" + "" + "}"; var lexer = new Lexer.Lexer(); var tokens = lexer.Lex(src); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); var binder = new Binder(); Assert.That( () => binder.Bind(new List<CompilationUnitSyntax>() { ast }), Throws.InstanceOf<KiwiSemanticException>() .With.Message.EqualTo("IfTrue and IfFalse expression Type must match")); }
public void TestExpressions(string statementSource, Type type) { var lexer = new Lexer.Lexer(); var tokens = lexer.Lex( string.Format( NamespaceSource, string.Format( ClassSource, string.Format(FunctionSource, statementSource), string.Empty, string.Empty))); var parser = new Parser.Parser(tokens); var ast = parser.Parse(); Assert.IsInstanceOf( type, ((ReturnStatementSyntax)((ScopeStatementSyntax)ast.Namespaces[0].Classes[0].Functions[0].Statements).Statements[0]).Expression); }