Example #1
0
        /// <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");
        }
Example #2
0
        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
            });
        }
Example #3
0
        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));
        }