/// <summary> /// parse non-math expressions /// </summary> public static Exp ParseExp(List <Token> tokens) { if (tokens.Count == 0) { return(Exp.Null); } else if (tokens.Count == 1) { Token tok = tokens[0]; switch (tok.Type) { case TokenType.String: return(Exp.Constant(tok.Value)); case TokenType.Char: return(Exp.Constant(tok.Value[0])); case TokenType.Number: if (tok.Value.IndexOf('.') == -1) { return(Exp.Constant(int.Parse(tok.Value))); } else { return(Exp.Constant(double.Parse(tok.Value))); } case TokenType.Identifier: switch (tok.Value) { case "null": return(Exp.Null); case "true": return(Exp.True); case "false": return(Exp.False); case "int": return(Exp.Int); case "float": return(Exp.Float); case "char": return(Exp.Char); case "bool": return(Exp.Bool); case "String": return(Exp.String); case "Object": return(Exp.Object); case "List": return(Exp.List); default: Exp c = locals.Find(tok.Value); if (c is null) { return(locals.NewVar(tok.Value)); } else { return(c); } } case TokenType.Parenthesis: // parenthesis if (tok.Expressions.Count == 1) { return(ParseExp(tok.Expressions[0])); } break; case TokenType.Brackets: // array return(new NewList { items = ParseArg(tok) }); case TokenType.Braces: // dictionary return(new NewDict { elements = ParseArg(tok) }); } } else { // starts with Token first = tokens[0]; if (first.Type == TokenType.Identifier) { if (first.Value == "new") { tokens.RemoveAt(0); // new int lastindex = tokens.Count - 1; Exp[] arg = ParseArg(tokens[lastindex]); tokens.RemoveAt(lastindex); // (..) return(new New { type = ParseExp(tokens), arg = arg }); } else if (first.Value == "function") { return(ParseLambda(tokens)); } } // ends with Token last = tokens[tokens.Count - 1]; tokens.RemoveAt(tokens.Count - 1); if (last.Type == TokenType.Parenthesis) { Token pre = tokens[tokens.Count - 1]; if (pre.Type == TokenType.Member) { tokens.RemoveAt(tokens.Count - 1); return(new Call { obj = ParseExp(tokens), name = pre.Value, arg = ParseArg(last) }); } else if (pre.Type == TokenType.Brackets) // generic call { Token pre2 = tokens[tokens.Count - 2]; if (pre2.Type == TokenType.Member) { tokens.RemoveAt(tokens.Count - 1); tokens.RemoveAt(tokens.Count - 1); return(new Call { obj = ParseExp(tokens), name = pre2.Value, arg = ParseArg(last), typeArgs = pre.Expressions.Select(x => ((TypeI)ParseExp(x)).type).ToArray() }); } } return(new Invoke { obj = ParseExp(tokens), arg = ParseArg(last) }); } else if (last.Type == TokenType.Brackets) { Exp collection = ParseExp(tokens); Exp[] indeces = ParseArg(last); // set generic type if (collection is TypeI t) { Type[] typeArgs = indeces.Select(x => ((TypeI)x).type).ToArray(); if (typeArgs.Length == 0) { return(new TypeI { type = t.type.MakeArrayType() }); } else { return(new TypeI { type = t.genericTypes[indeces.Length].MakeGenericType(typeArgs) }); } } if (indeces.Length == 0) { // [] operator return(new EmptyIndex { obj = collection }); } else if (indeces.Length > 1) { throw new Exception("syntax error, unexpected ',', expecting ']'"); } Exp index = indeces[0]; // slice notation if (index is Operation.Colon colon1) { if (colon1.left is Operation.Colon colon2) // step { return(new SliceIndex { obj = collection, start = colon2.left, end = colon2.right, step = colon1.right }); } else // step omitted { return(new SliceIndex { obj = collection, start = colon1.left, end = colon1.right, step = Exp.Null }); } } return(new ExpTree.Index { obj = collection, index = index }); } else if (last.Type == TokenType.Member) { Exp obj = ParseExp(tokens); string name = last.Value; if (obj is NamespaceI ns) { if (ns.fields.TryGetValue(name, out Exp field)) { return(field); } else { throw new Exception($"The type or namespace name '{name}' does not exist in the namespace '{ns.name}'"); } } return(Exp.Member(obj, name)); } } throw new Exception("Unable to parse expression"); }
public static Block ParseBlock(List <Expression> expressions, bool islocal = true) { Scope lcp = null; if (islocal) { lcp = locals; locals = new Scope(); locals.previous = lcp; } var chunk = new List <Exp>(); Expression expr; var ifparts = new Stack <If>(); for (int i = 0; i < expressions.Count; i++) { expr = expressions[i]; if (expr.cmd == Statement.None && expr.operators is null && expr.tokens.Count == 0) { continue; } switch (expr.cmd) { case Statement.Import: Import(fpath(expr.tokens)); break; case Statement.Using: Using(expr.tokens); break; case Statement.Class: var type = new Reflection.Type(expr); globals.Add(type.Name, Exp.Constant(type)); break; case Statement.Cil: globals.Add(expr.tokens[0].Value, Exp.Constant(ParseCil(expr.tokens))); break; case Statement.Function: ParseFunc(expr.tokens); break; case Statement.Return: chunk.Add(new Return { value = ParseExp(expr) }); break; case Statement.If: Exp test = ParseExp(expr.tokens[0].Expressions[0]); Block body = ParseBlock(expr.tokens[1]); If ifthen = new If { test = test, body = body }; ifparts.Push(ifthen); if (i + 1 == expressions.Count || expressions[i + 1].cmd != Statement.Else) { chunk.Add(IfThenElse(ifparts)); } break; case Statement.Else: if (expr.tokens[0].Type == TokenType.Parenthesis) // else if { goto case Statement.If; } else // else { body = ParseBlock(expr.tokens[0]); chunk.Add(IfThenElse(ifparts, body)); } break; case Statement.For: Token paren = expr.tokens[0]; if (paren.Expressions.Count == 3) { Exp init = ParseExp(paren.Expressions[0]); chunk.Add(init); test = ParseExp(paren.Expressions[1]); Exp step = ParseExp(paren.Expressions[2]); body = ParseBlock(expr.tokens[1]); var loop = new While { test = test, body = body, step = step }; chunk.Add(loop); } else if (paren.Expressions.Count == 1) { var forEach = new ForEach(); forEach.var = (Variable)ParseExp(paren.Expressions[0].operands[0]); forEach.collection = ParseExp(paren.Expressions[0].tokens); forEach.body = ParseBlock(expr.tokens[1]); chunk.Add(forEach); } break; case Statement.While: chunk.Add(new While { test = ParseExp(expr.tokens[0].Expressions[0]), body = ParseBlock(expr.tokens[1]) }); break; case Statement.Break: chunk.Add(new Break()); break; case Statement.Continue: chunk.Add(new Continue()); break; case Statement.Switch: { var cases = new List <SwitchCase>(); Exp switchValue = ParseExp(expr.tokens[0].Expressions[0]); Exp caseValue = null; var bodybuilder = new List <Expression>(); bool jump = true; foreach (Expression e in expr.tokens[1].Expressions) { if (e.cmd == Statement.Case) { if (caseValue != null) { cases.Add(new SwitchCase { test = caseValue, body = ParseBlock(bodybuilder) }); } // new case caseValue = ParseExp(e); if (jump) { if (!(caseValue is Constant)) { jump = false; } } bodybuilder = new List <Expression>(); } else { bodybuilder.Add(e); } } cases.Add(new SwitchCase { test = caseValue, body = ParseBlock(bodybuilder) }); // try convert to jumptable if (jump) { var table = new Dictionary <dynamic, Block>(); foreach (SwitchCase c in cases) { table.Add(((Constant)c.test).value, c.body); } chunk.Add(new JumpTable { value = switchValue, table = table }); } else { chunk.Add(new Switch { switchValue = switchValue, cases = cases.ToArray() }); } break; } case Statement.Echo: Exp msg = ParseExp(expr); chunk.Add(new Invoke { obj = Exp.Echo, arg = new[] { msg } }); break; case Statement.Throw: msg = ParseExp(expr); chunk.Add(new Throw { message = msg }); break; case Statement.Var: if (expr.operators is null) { string name = expr.tokens[0].Value; locals.NewVar(name); } else if (expr.operators[0] == Op.Assign) { string name = expr.operands[0][0].Value; locals.NewVar(name); goto default; } break; default: chunk.Add(ParseExp(expr)); break; } } if (islocal) { var body = new Block { expressions = chunk }; body.SetVariables(); locals = lcp; return(body); } return(new Block { expressions = chunk }); }
public static Delegate ParseCil(List <Token> tokens) { // initialize OPs if (DictOp is null) { InitializeDictOp(); } var lcp = locals; locals = new Scope { previous = globals }; string name = tokens[0].Value; Type[] parameterTypes = tokens[1].Expressions .Select(x => ((TypeI)ParseExp(x)).type) .ToArray(); Type returnType; List <Token> retToks = tokens.Skip(2).Take(tokens.Count - 3).ToList(); if (retToks.Count == 0) { returnType = typeof(void); } else { returnType = ((TypeI)ParseExp(retToks)).type; } var meth = new DynamicMethod(name, returnType, parameterTypes, typeof(jsc).Module); var il = meth.GetILGenerator(); var body = tokens[tokens.Count - 1]; OpCode op; dynamic arg = null; foreach (Expression e in body.Expressions) { if (e.tokens.Count == 0) // none { continue; } // label if (e.operators != null && e.operators.Count == 1 && e.operators[0] == Op.Colon) { string lbl = e.operands[0][0].Value; Label label = il.DefineLabel(); locals.Add(lbl, Exp.Constant(label)); il.MarkLabel(label); } string opName = e.tokens[0].Value; // exceptions if (e.cmd == Statement.Var) { e.tokens.RemoveAt(0); Type type = ((TypeI)ParseExp(e.tokens)).type; locals.Add(opName, Exp.Constant(il.DeclareLocal(type))); continue; } else if (opName == "ldarg_ref") { il.Emit(OpCodes.Ldarg_0); e.tokens.RemoveAt(0); il.Emit(OpCodes.Ldc_I4, (int)ParseExp(e.tokens).Eval()); il.Emit(OpCodes.Ldelem_Ref); continue; } // parse opcode if (DictOp.TryGetValue(opName, out OpCode value)) { op = value; } else { throw new Exception($"'{opName}' is not an OpCode"); } // parse arg if (e.tokens.Count == 1) { arg = null; } else if (e.tokens.Count >= 2) { e.tokens.RemoveAt(0); arg = ParseExp(e.tokens).Eval(); } // emit if (arg is null) { il.Emit(op); } else { il.Emit(op, arg); } } locals = lcp; Type delType; if (returnType == typeof(void)) { delType = System.Linq.Expressions.Expression.GetActionType(parameterTypes); } else { Type[] tArgs = parameterTypes.Concat(new[] { returnType }).ToArray(); delType = System.Linq.Expressions.Expression.GetFuncType(tArgs); } return(meth.CreateDelegate(delType)); }