private void CreateTypeSymbols(TranslationUnit unit) { foreach (var decl in unit.Source.TypeDeclarations) { unit.AddTask(() => { Type type = ConvertType(unit, unit.Scope, decl.Type); if (type == null) { return(Error.UnresolvableType(decl.Type)); } if (type == Type.UnknownType) { throw new InvalidOperationException("Unknown type not allows in declaration"); } if (type == Type.VoidType) { throw new InvalidOperationException("Void type may not be aliased!"); } unit.Module.Symbols.Add(new Symbol(Type.MetaType, decl.Name) { IsConst = true, IsExported = decl.IsExported, Initializer = new TypeLiteral(type), }); return(CompilerError.None); }); } }
private void ImportSymbolsIntoUnit(TranslationUnit unit) { foreach (var name in unit.Source.Imports) { unit.AddTask(() => { var sym = GlobalScope.FindNamedSymbol(name, Type.ModuleType, true); if (sym == null) { return(Error.UnknownImport(name)); } var mod = sym.GetValue <Module>(); if (mod == null) { throw new InvalidOperationException("imported module is not a constant!"); } unit.Imports.Push(mod.Symbols); return(CompilerError.None); }); } }
private Statement ConvertStatement(TranslationUnit unit, IScope scope, Grammar.Statement stmt, BlockContext context) { if (stmt is Grammar.Block block) { var result = new Block(); unit.AddTask(() => { var sequence = new List <Statement>(); var blockscope = scope; foreach (var sub in block) { if (sub is Declaration decl) { // TODO: Allow CreateSymbol initializer to access the self-defined symbol var err = CreateSymbol(unit, blockscope, decl, out var sym); if (err != CompilerError.None) { return(err); } sym.Kind = SymbolKind.Local; blockscope = new ExtendingScope(blockscope, sym); if (decl.Value != null) { var init = new ExpressionStatement(); unit.AddTask(() => { if (sym.Initializer == null) { return(Error.InvalidExpression(decl.Value)); } init.Expression = sym.Initializer; return(Error.None); }); sequence.Add(init); } } else { var substmt = ConvertStatement(unit, blockscope, sub, context); if (substmt == null) { return(Error.UntranslatableStatement(sub)); } sequence.Add(substmt); } } result.Statements = sequence; return(Error.None); }); return(result); } else if (stmt is Grammar.ExpressionStatement expr) { var exec = new ExpressionStatement(); unit.AddTask(() => { var list = ConvertExpression(unit, scope, expr.Expression); if (list == null) { return(Error.InvalidExpression(expr.Expression)); } if (list.Count > 1) { return(Error.AmbiguousExpression(expr.Expression, list)); } exec.Expression = list.Single(); if (exec.Expression == null) { return(Error.InvalidExpression(expr.Expression)); } return(Error.None); }); return(exec); } else if (stmt is Grammar.FlowBreakStatement flow) { switch (flow.Type) { case FlowBreakType.Return: { var @return = new ReturnStatement(); if (flow.Value != null) { unit.AddTask(() => { var options = ConvertExpression(unit, scope, flow.Value); @return.Result = SelectFitting(options, context.EnclosingType.ReturnType); if (@return.Result == null) { return(Error.InvalidExpression(flow.Value)); } return(Error.None); }); } return(@return); } default: throw new NotSupportedException($"{flow.Type} is not supported yet."); } } else if (stmt is WhileLoopStatement loop) { var s = new WhileLoop(); unit.AddTask(() => { s.Condition = ConvertExpression(unit, scope, loop.Condition).Single(); if (s.Condition == null) { return(Error.InvalidExpression(loop.Condition)); } return(Error.None); }); unit.AddTask(() => { s.Body = ConvertStatement(unit, scope, loop.Body, context); if (s.Body == null) { return(Error.UntranslatableStatement(loop.Body)); } return(Error.None); }); return(s); } else { throw new NotSupportedException($"The statement type {stmt?.GetType()?.Name ?? "?"} is not supported yet."); } }
/// <summary> /// Converts the given abstract expression into a list of possible AST expressions. /// Throws an exception if the translation was not possible because of unfinished symbols /// </summary> /// <param name="unit"></param> /// <param name="scope"></param> /// <param name="value"></param> /// <param name="context"></param> /// <returns></returns> private IReadOnlyList <Expression> ConvertExpression(TranslationUnit unit, IScope scope, Grammar.Expression value, ExpressionContext context = null) { if (value is NumberLiteral num) { var literals = new List <Expression>(); // try hex first, then decimal if (ulong.TryParse(num.Value.Substring(2), NumberStyles.HexNumber, SystemFormat, out ulong u)) { if (u <= 0xFF) { literals.Add(new ByteLiteral((byte)u)); } literals.Add(new UIntLiteral(u)); } else if (ulong.TryParse(num.Value, NumberStyles.Integer, SystemFormat, out u)) { if (u <= 0xFF) { literals.Add(new ByteLiteral((byte)u)); } literals.Add(new UIntLiteral(u)); } // try hex first, then decimal if (long.TryParse(num.Value.Substring(2), NumberStyles.HexNumber, SystemFormat, out long i)) { literals.Add(new IntLiteral(i)); } else if (long.TryParse(num.Value, NumberStyles.Integer, SystemFormat, out i)) { literals.Add(new IntLiteral(i)); } // also try double separated if (double.TryParse(num.Value, NumberStyles.Number, SystemFormat, out double dbl)) { literals.Add(new RealLiteral(dbl)); } return(literals.ToArray()); } else if (value is Grammar.StringLiteral str) { // this could be translated into an ArrayLiteral, // but this allows a certain degree of optimization return(new[] { new StringLiteral(str.Text) }); } else if (value is CharacterLiteral chr) { return(new[] { new CharLiteral(chr.Codepoint) }); } else if (value is ArrayLiteral array) { var expr = new ArrayExpression(); expr.Items = new Expression[array.Values.Count]; for (int i = 0; i < expr.Items.Length; i++) { int idx = i; var elem = ConvertExpression(unit, scope, array.Values[idx]); if (elem == null) { Error.InvalidExpression(value); return(null); } expr.Items[idx] = elem.Single(); } if (expr.Items.Any(i => i is null)) { throw Error.Critical("Not all array elements could be translated!"); } var type = FindCommonType(expr.Items.Select(i => i.Type)); if (type == null) { throw Error.NoCommmonType(); } expr.ItemType = type; return(new[] { expr }); } else if (value is Grammar.FunctionLiteral function) { var type = ConvertType(unit, scope, function.Type) as FunctionType; if (type == null) { throw Error.UnresolvableType(function.Type); } var fun = new UserFunction(type); var paramscope = new SimpleScope(); for (int i = 0; i < type.Parameters.Length; i++) { var param = type.Parameters[i]; paramscope.Add(new Symbol(param.Type, param.Name) { Kind = SymbolKind.Parameter, ParameterIndex = i, }); } fun.Scope.Push(scope); fun.Scope.Push(paramscope); var ctx = new BlockContext { EnclosingType = type }; // IMPORTANT: // Use task system here as a function literal body is independent from its type // and can be translated completly separated from the rest of the expression unit.AddTask(() => { var body = ConvertStatement(unit, fun.Scope, function.Body, ctx); if (body == null) { return(Error.UntranslatableStatement(function.Body)); } fun.Body = body; return(Error.None); }); unit.Module.Functions.Add(fun); return(new[] { new FunctionLiteral(fun) }); } else if (value is VariableReference vref) { var syms = scope.Where(s => s.Name.ID == vref.Variable).ToArray(); if (syms.Length == 0) { throw Error.SymbolNotFound(vref.Variable); } return(syms.Select(s => new SymbolReference(s)).ToArray()); } else if (value is UnaryOperation unop) { var val = ConvertExpression(unit, scope, unop.Operand); if (val == null) { throw Error.InvalidExpression(unop.Operand); } var results = new List <FunctionCall>(); foreach (var item in val) { var type = FunctionType.CreateUnaryOperator(Type.UnknownType, item.Type); var sig = new Signature(type, unop.Operator); if (scope.HasSymbol(sig) == false) { continue; } results.Add(new FunctionCall(new SymbolReference(scope[sig]), new[] { item })); } if (results.Count == 0) { throw Error.UnknownOperator(unop); } return(results); } else if (value is BinaryOperation binop) { var lhslist = ConvertExpression(unit, scope, binop.LeftHandSide); var rhslist = ConvertExpression(unit, scope, binop.RightHandSide); var results = new List <FunctionCall>(); foreach (var lhs in lhslist) { foreach (var rhs in rhslist) { var type = FunctionType.CreateBinaryOperator( returnType: Type.UnknownType, leftType: lhs.Type, rightType: rhs.Type); var sig = new Signature(type, binop.Operator); if (scope.HasSymbol(sig) == false) { continue; } results.Add(new FunctionCall(new SymbolReference(scope[sig]), new[] { lhs, rhs })); } } if (results.Count == 0) { Error.UnknownOperator(binop); } return(results); } else if (value is FunctionCallExpression fncall) { var results = new List <FunctionCall>(); var functions = ConvertExpression(unit, scope, fncall.Value); foreach (var func in functions) { var type = func.Type as FunctionType; if (type == null) { continue; } var call = new FunctionCall(); call.Functor = func; var arglist = new Expression[type.Parameters.Length]; var paramset = new HashSet <Parameter>(type.Parameters); foreach (var arg in fncall.PositionalArguments) { var param = paramset.SingleOrDefault(p => p.Position == arg.Position); if (param == null) { continue; } arglist[param.Position] = SelectFitting( ConvertExpression(unit, scope, arg.Value), param.Type); if (arglist[param.Position] == null) { continue; } paramset.Remove(param); } foreach (var arg in fncall.NamedArguments) { var param = paramset.SingleOrDefault(p => p.Name == arg.Name); if (param == null) { continue; } arglist[param.Position] = ConvertExpression(unit, scope, arg.Value).Single(); if (arglist[param.Position] == null) { continue; } paramset.Remove(param); } if (paramset.Count > 0) { continue; } call.Arguments = arglist; results.Add(call); } if (results.Count == 0) { throw Error.Critical($"Unknown function {fncall.Value} with fitting argument list."); } return(results); } else { throw new NotSupportedException($"The expression type '{value?.GetType()?.Name ?? "?"}' is not supported yet."); } }
private Type ConvertType(TranslationUnit unit, IScope scope, AstType asttype) { if (asttype is LiteralType lt) { if (lt == LiteralType.Void) { return(Type.VoidType); } else if (lt == LiteralType.Unknown) { return(Type.UnknownType); } else { throw new NotSupportedException("Unknown literal type!"); } } else if (asttype is NamedTypeLiteral ntl) { var sym = scope.FindNamedSymbol(ntl.Name, Type.MetaType, true); if (sym != null) { return(sym.GetValue <Type>()); } else { return(null); } } else if (asttype is EnumTypeLiteral etl) { return(new EnumType(etl.Items)); } else if (asttype is ArrayTypeLiteral atl) { var type = new ArrayType { Dimensions = atl.Dimensions }; unit.AddTask(() => { type.ElementType = ConvertType(unit, scope, atl.ElementType); if (type.ElementType == null) { return(Error.UnresolvableType(atl.ElementType)); } return(CompilerError.None); }); return(type); } else if (asttype is RecordTypeLiteral rtl) { var type = new RecordType(); type.Members = new List <RecordMember>(); foreach (var m in rtl.Fields) { var mem = new RecordMember(type, m.Name); unit.AddTask(() => { var ftype = ConvertType(unit, scope, m.Type); if (ftype == null) { return(Error.UnresolvableType(m.Type)); } var member = new RecordMember(type, m.Name) { Type = ftype, }; return(Error.None); }); if (m.Value != null) { unit.AddTask(() => { mem.Initializer = ConvertExpression(unit, scope, m.Value).Single(); if (mem.Initializer == null) { return(Error.InvalidExpression(m.Value)); } return(Error.None); }); } type.Members.Add(mem); } return(type); } else if (asttype is ReferenceTypeLiteral rftl) { var type = new ReferenceType(); unit.AddTask(() => { type.ObjectType = ConvertType(unit, scope, rftl.ObjectType); if (type.ObjectType == null) { return(Error.UnresolvableType(rftl.ObjectType)); } return(CompilerError.None); }); return(type); } else if (asttype is FunctionTypeLiteral ftl) { var type = new FunctionType(); unit.AddTask(() => { type.ReturnType = ConvertType(unit, scope, ftl.ReturnType); if (type.ReturnType == null) { return(Error.UnresolvableType(ftl.ReturnType)); } return(CompilerError.None); }); var @params = new Parameter[ftl.Parameters.Count]; for (int i = 0; i < ftl.Parameters.Count; i++) { var par = ftl.Parameters[i]; var p = new Parameter(type, par.Name, i) { Flags = par.Prefix, }; // Set "in" as default if neither in nor out is given if (!p.Flags.HasFlag(ParameterFlags.In) && !p.Flags.HasFlag(ParameterFlags.Out)) { p.Flags |= ParameterFlags.In; } if (par.Type != null) { unit.AddTask(() => { p.Type = ConvertType(unit, scope, par.Type); if (p.Type == null) { return(Error.UnresolvableType(par.Type)); } return(CompilerError.None); }); } if (par.Value != null) { unit.AddTask(() => { p.Initializer = ConvertExpression(unit, scope, par.Value).Single(); if (p.Initializer == null) { return(Error.InvalidExpression(par.Value)); } return(CompilerError.None); }); } @params[i] = p; } type.Parameters = @params; return(type); } else { throw new NotSupportedException($"{asttype.GetType().Name} is not supported yet!"); } }