private static void ValidateEntryPoint(CodeGenerator generator, RppOptions options, Diagnostic diagnostic) { if (options.Library == false && !generator.HasMain()) { diagnostic.Error(101, "Program doesn't contain a valid entry point"); } }
public static Type CodeGenAndGetType(RppProgram program, string typeName, Diagnostic diagnostic) { var assembly = CodeGen(program, diagnostic); Type arrayTy = assembly.GetType(typeName); Assert.IsNotNull(arrayTy); return arrayTy; }
public override IRppNode Analyze(SymbolTable scope, Diagnostic diagnostic) { // TODO should be unified with RppFuncCall and rethink how types for closures are figureout. // we should use constraints and type inference only, not this kind of hacks when we check target // closure signature and use types from there // Skip closures because they may have missing types _arguments = NodeUtils.AnalyzeWithPredicate(scope, _arguments, node => !(node is RppClosure), diagnostic); Type.Resolve(scope); RType targetType = Type.Value; if (NeedToInferGenericArguments(targetType)) { RType inferredTargetType; Constructor = FindGenericConstructor(targetType, out inferredTargetType); Type = new ResolvableType(inferredTargetType); } else { Constructor = FindConstructor(targetType); } _arguments = RppFuncCall.ReplaceUndefinedClosureTypesIfNeeded(_arguments, Constructor.Parameters, new List<RType>()); NodeUtils.AnalyzeWithPredicate(scope, _arguments, node => node is RppClosure, diagnostic); return this; }
public static Assembly CodeGen(RppProgram program, Diagnostic diagnostic) { SymbolTable scope = new SymbolTable(null); RppTypeSystem.PopulateBuiltinTypes(scope); WireRuntime(scope); Assembly stdlib = RppCompiler.FindStdlib(); if (stdlib != null) { WireAssembly(scope, stdlib); } CodeGenerator generator = new CodeGenerator(program, "TestAssembly.dll"); Type2Creator typeCreator = new Type2Creator(); program.Accept(typeCreator); program.PreAnalyze(scope); InheritanceConfigurator2 configurator = new InheritanceConfigurator2(); program.Accept(configurator); CreateRType createRType = new CreateRType(diagnostic); program.Accept(createRType); if (diagnostic.Errors.Any()) { return null; } SemanticAnalyzerStage1 semanticStage1 = new SemanticAnalyzerStage1(diagnostic); program.Accept(semanticStage1); program.Analyze(scope, diagnostic); if (diagnostic.Errors.Any()) { return null; } SemanticAnalyzer semantic = new SemanticAnalyzer(diagnostic); program.Accept(semantic); if (diagnostic.Errors.Any()) { return null; } InitializeNativeTypes initializeNativeTypes = new InitializeNativeTypes(generator.Module); program.Accept(initializeNativeTypes); CreateNativeTypes createNativeTypes = new CreateNativeTypes(); program.Accept(createNativeTypes); generator.Generate(); return generator.Assembly; }
public static CodeGenerator Compile(Action<RppProgram> parseFactory, Diagnostic diagnostic, [CanBeNull] Assembly stdlibAssembly, string fileName = "<buffer>") { RppProgram program = new RppProgram(); SymbolTable runtimeScope = new SymbolTable(); RppTypeSystem.PopulateBuiltinTypes(runtimeScope); WireRuntime(runtimeScope); if (stdlibAssembly != null) { WireAssembly(runtimeScope, stdlibAssembly); } try { parseFactory(program); CodeGenerator generator = new CodeGenerator(program, fileName); Type2Creator typeCreator = new Type2Creator(); program.Accept(typeCreator); program.PreAnalyze(runtimeScope); InheritanceConfigurator2 configurator = new InheritanceConfigurator2(); program.Accept(configurator); CreateRType createRType = new CreateRType(diagnostic); program.Accept(createRType); SemanticAnalyzerStage1 semanticStage1 = new SemanticAnalyzerStage1(diagnostic); program.Accept(semanticStage1); program.Analyze(runtimeScope, null); SemanticAnalyzer semantic = new SemanticAnalyzer(diagnostic); program.Accept(semantic); InitializeNativeTypes initializeNativeTypes = new InitializeNativeTypes(generator.Module); program.Accept(initializeNativeTypes); CreateNativeTypes createNativeTypes = new CreateNativeTypes(); program.Accept(createNativeTypes); generator.Generate(); return generator; } catch (SemanticException e) { diagnostic.Error(e.Code, e.Message); return null; } catch (ParserException e) { diagnostic.Error(e.Code, e.Message); return null; } }
public override IRppNode Analyze(SymbolTable scope, Diagnostic diagnostic) { Condition = (IRppExpr) Condition.Analyze(scope, diagnostic); ThenExpr = (IRppExpr) ThenExpr.Analyze(scope, diagnostic); ElseExpr = (IRppExpr) ElseExpr.Analyze(scope, diagnostic); Type = ThenExpr.Type; return this; }
public override IRppNode Analyze(SymbolTable scope, Diagnostic diagnostic) { RType thisType = scope.GetEnclosingType(); if (thisType == null) { throw new Exception("Can't find enclosing type for this"); } Type = new ResolvableType(thisType); return this; }
public void ResolveType(SymbolTable scope, Diagnostic diagnostic) { if (Type.IsUndefined()) { // TODO this is not easy to fix because field creates accessors which are functions and they are // processed before Analyze, so type of field may not be infered. Solution is to delay accessor synthize // to later phases when signatures of all functions are known. throw SemanticExceptionFactory.CantInferType(Token); } Type?.Resolve(scope); }
public override IRppNode Analyze(SymbolTable scope, Diagnostic diagnostic) { Condition = (IRppExpr) Condition.Analyze(scope, diagnostic); Body = Body.Analyze(scope, diagnostic); if (!Equals(Condition.Type, ResolvableType.BooleanTy)) { throw new Exception("Condition should be boolean not " + Condition.Type); } return this; }
/// <summary> /// So we have pattern like this: /// case [Pattern] => [Expr] /// we need to figure out type of [Expr] but it can depend on variables spawned in /// [Pattern], so we need to get thise variables (see RppMatchPattern.DeclareVariables()) /// and add them to the scope and then anaylize [Expr] /// </summary> public override IRppNode Analyze(SymbolTable scope, Diagnostic diagnostic) { Pattern = (RppMatchPattern) Pattern.Analyze(scope, diagnostic); SymbolTable localScope = new SymbolTable(scope); RType inputType = GetInputType(localScope); IEnumerable<IRppExpr> locals = Pattern.DeclareVariables(inputType); NodeUtils.Analyze(localScope, locals, diagnostic); Expr = (IRppExpr) Expr.Analyze(localScope, diagnostic); return this; }
private static int RunAndReturnExitCode(RppOptions options) { Diagnostic diagnostic = new Diagnostic(); RppCompiler.CompileAndSave(options, diagnostic); diagnostic.Report(); if (diagnostic.Errors.Any()) { return 1; } return 0; }
public void NonInitializedLocalVar() { const string code = @" object Main { def main: Unit = { val k: Int } } "; Diagnostic diagnostic = new Diagnostic(); Utils.ParseAndAnalyze(code, diagnostic); Assert.AreEqual(1, diagnostic.Errors.Count()); Assert.AreEqual(102, diagnostic.Errors.First().Code); }
public override IRppNode Analyze(SymbolTable scope, Diagnostic diagnostic) { if (InitExpr is RppEmptyExpr && IsLocalSemantic) { diagnostic.Error(102, "local variable must be initialized"); return this; } // Don't capture variables declared inside closure CanBeCaptured = scope.GetEnclosingType()?.Name != RppClosure.TempClosureTypeName; // We have 2 cases when type is omited, so we need to get it from initializing expression // and when type is specified so we need to resolve it and if there is a closure, propagate that // to init expression if (Type.IsDefined()) { Type.Resolve(scope); InitExpr = TypeInference.ReplaceUndefinedClosureTypesIfNeeded(InitExpr, Type, new List<RType>()); InitExpr = (IRppExpr) InitExpr.Analyze(scope, diagnostic); } else { InitExpr = (IRppExpr) InitExpr.Analyze(scope, diagnostic); Type = InitExpr.Type; } if (IsLocalSemantic) { scope.AddLocalVar(Name, Type.Value, this); } if (!(InitExpr is RppEmptyExpr)) { if (ImplicitCast.CanCast(InitExpr.Type.Value, Type.Value)) { InitExpr = ImplicitCast.CastIfNeeded(InitExpr, Type.Value); } else { throw SemanticExceptionFactory.TypeMismatch(Token, Type.Value.Name, InitExpr.Type.Value.Name); } } return this; }
public override IRppNode Analyze(SymbolTable scope, Diagnostic diagnostic) { base.Analyze(scope, diagnostic); // Rewrite assignment to function call when assigned to array, e.g. array(index) = value => array.update(index, value) if (Left is RppSelector) { RppSelector selector = (RppSelector) Left; if (selector.Path.Name == "apply") { RppFuncCall applyFuncCall = selector.Path as RppFuncCall; if (applyFuncCall != null && applyFuncCall.Function.DeclaringType.Name == "Array") { RppSelector updateArray = new RppSelector(selector.Target, new RppFuncCall("update", new List<IRppExpr> {applyFuncCall.Args.First(), Right})); return updateArray.Analyze(scope, diagnostic); } } else if (selector.Path is RppFieldSelector) // Rewrite assignment to field as a call to setter of the field { RppFieldSelector fieldSelector = (RppFieldSelector) selector.Path; return CallSetter(selector.Target, fieldSelector.Field, Right).Analyze(scope, diagnostic); } } else if (Left is RppId) { RppId id = (RppId) Left; if (id.IsField && !id.IsFieldAccessedDirectly) { return CallSetter(new RppThis(), id.Field, Right).Analyze(scope, diagnostic); } } if (!Equals(Left.Type, Right.Type)) { if (!Left.Type.Value.IsAssignable(Right.Type.Value)) { throw SemanticExceptionFactory.TypeMismatch(Right.Token, Left.Type.Value.Name, Right.Type.Value.Name); } } return this; }
public static void CompileAndSave(RppOptions options, Diagnostic diagnostic) { string outFileName = GetOutputFileName(options); Assembly stdlib = null; if (!options.Nostdlib) { stdlib = FindStdlib(); } CodeGenerator generator = Compile(program => Parse(options.InputFiles, program), diagnostic, stdlib, outFileName); if (generator != null) { ValidateEntryPoint(generator, options, diagnostic); if (!diagnostic.Errors.Any()) { generator.Save(options.Library ? ApplicationType.Library : ApplicationType.Application); } } }
public override IRppNode Analyze(SymbolTable scope, Diagnostic diagnostic) { if (TargetType == null) { throw new Exception("TargetType should be specified before anaylyze is called"); } RType classType = TargetType; // TODO It's kinda weird to have resolution here and not in the scope, because similar // lookup is done for methods while (classType != null && Field == null) { Field = classType.Fields.FirstOrDefault(f => f.Name == Name); if (Field != null) { break; } classType = classType.BaseType; } if (Field == null) { var functions = scope.LookupFunction(Name); if (functions.Any(f => f.Parameters.IsEmpty())) { RppFuncCall funcCall = new RppFuncCall(Name, Collections.NoExprs); return funcCall.Analyze(scope, diagnostic); } throw SemanticExceptionFactory.ValueIsNotMember(Token, TargetType.ToString()); } Debug.Assert(classType != null, "obj != null"); Type = new ResolvableType(Field.Type); return this; }
public override IRppNode Analyze(SymbolTable scope, Diagnostic diagnostic) { Value = (IRppExpr) Value.Analyze(scope, diagnostic); RppVar declIn = new RppVar(MutabilityFlag.MfVal, "<in>", Value.Type, Value); declIn.Analyze(scope, diagnostic); CaseClauses = NodeUtils.Analyze(scope, CaseClauses, diagnostic); Type = CheckCommonType(CaseClauses, Token).AsResolvable(); RppVar declOut = new RppVar(MutabilityFlag.MfVar, "<out>", Type, new RppDefaultExpr(Type)); RppId declInId = new RppId("<in>", declIn); declInId.Analyze(scope, diagnostic); RppId declOutId = new RppId("<out>", declOut); RppMatchingContext ctx = new RppMatchingContext(); var ifC = Create(declInId, declOutId, CaseClauses, ctx); var expr = new RppBlockExpr(List<IRppNode>(declIn, ifC)) {Exitable = true}; SymbolTable matchScope = new SymbolTable(scope); RppBlockExpr matchBlock = new RppBlockExpr(List<IRppNode>(declOut, expr, declOutId)); return matchBlock.Analyze(matchScope, diagnostic); }
public override IRppNode Analyze(SymbolTable scope, Diagnostic diagnostic) { _type.Resolve(scope); _patterns = NodeUtils.Analyze(scope, _patterns, diagnostic).ToArray(); TypeSymbol companionObjectSymbol = scope.LookupObject(_type.Name.Name); if (companionObjectSymbol != null) { RppMethodInfo unapplyMethod = FindUnapply(companionObjectSymbol.Type); if (unapplyMethod == null) { throw new Exception("Can't find unapply method or amount of parameters is wrong"); } _unapplyMethod = unapplyMethod; } else { throw new Exception("Can't find companion object!"); } return this; }
public static RppProgram ParseAndAnalyze(string code, Diagnostic diagnostic) { RppProgram program = Parse(code); CodeGen(program, diagnostic); return program; }
public override IRppNode Analyze(SymbolTable scope, Diagnostic diagnostic) { Debug.Assert(Scope != null, "Scope != null"); NodeUtils.Analyze(scope, _nested, diagnostic); SymbolTable constructorScope = new SymbolTable(Scope, Type, null); _classParams = NodeUtils.Analyze(Scope, _classParams, diagnostic); _fields = NodeUtils.Analyze(Scope, _fields, diagnostic); _constructors = NodeUtils.Analyze(constructorScope, _constructors, diagnostic); _funcs = (List<RppFunc>) NodeUtils.Analyze(Scope, _funcs, diagnostic); // TODO perhaps should be fixed return this; }
public static Type ParseAndCreateType(string code, string typeName, Diagnostic diagnostic) { RppProgram program = Parse(code); Assert.IsNotNull(program); return CodeGenAndGetType(program, typeName, diagnostic); }
public static IEnumerable<Type> ParseAndCreateTypes(string code, IEnumerable<string> typesNames, Diagnostic diagnostic) { RppProgram program = Parse(code); var assembly = CodeGen(program, diagnostic); return typesNames.Select(assembly.GetType); }
public ResolveParamTypes(Diagnostic diagnostic) { _diagnostic = diagnostic; }
public CreateRType(Diagnostic diagnostic) { _diagnostic = diagnostic; }
public void ResolveGenericTypeConstraints(SymbolTable scope, Diagnostic diagnostic) { NodeUtils.Analyze(scope, TypeParams, diagnostic); }
public static void Main() { const string code = @" abstract class XIterator[+A] { def hasNext: Boolean def next(): A def copy(): XIterator[A] protected def foreach(f: A => Unit): Unit = while (hasNext()) f(next()) def toList: XList[A] = { var res = XList[A]() foreach((item) => { res = new XCons(item, res) }) res.reverse() } def count: Int = { var c = 0 foreach(item => c = c + 1) c } def toArray[B <: A]: Array[B] = { val res = new Array[B](count()) var index = 0 foreach((item) => { res(index) = next() index = index + 1 }) res } } abstract class XIterable[+A] { def iterator: XIterator[A] } class XListIterator[A](var list: XList[A]) extends XIterator[A] { override def hasNext: Boolean = !list.isEmpty override def next(): A = { if (list.isEmpty) throw new Exception val item = list.head list = list.tail item } override def copy(): XIterator[A] = new XListIterator(list) } class XArrayIterator[A](var array: Array[A]) extends XIterator[A] { private var index: Int = 0 override def hasNext: Boolean = array.length > index override def next(): A = { val item = array(index) index += 1 item } override def copy(): XIterator[A] = new XArrayIterator(array) } class XMapIterator[A, U](val iter: XIterator[A], val f: A => U) extends XIterator[U] { override def hasNext(): Boolean = iter.hasNext() override def next(): U = f(iter.next()) override def count(): Int = iter.count() override def copy(): XIterator[U] = new XMapIterator(iter.copy(), f) } class XFilterIterator[A](val iter: XIterator[A], val f: A => Boolean) extends XIterator[A] { private var item: Option[A] = None calcNext() private def calcNext(): Unit = { while (iter.hasNext && item.isEmpty) { val it = iter.next() if (f(it)) { item = Some[A](it) } } } override def hasNext: Boolean = item.isDefined override def next(): A = { val nextItem = item.get calcNext() nextItem } override def copy(): XIterator[A] = new XFilterIterator(iter.copy(), f) } abstract class XList[+A] extends XIterable[A] { def head: A def tail: XList[A] def isEmpty: Boolean def asStream: XIterator[A] = iterator() override def iterator: XIterator[A] = new XListIterator[A](this) def reverse: XList[A] = { val iter = iterator() val k: A = iter.next() var res = XList[A]() while (iter.hasNext()) { res = new XCons[A](iter.next(), res) } res } def map[U](f: A => U): XList[U] = XFunc.map[A, U](iterator, f).toList } object XFunc { def map[A, U](iter: XIterator[A], f: A => U): XIterator[U] = new XMapIterator(iter, f) } object XNil extends XList[Nothing] { override def isEmpty: Boolean = true override def head: Nothing = throw new Exception override def tail: XList[Nothing] = throw new Exception } class XCons[A](val _head: A, val _tail: XList[A]) extends XList[A] { override def isEmpty: Boolean = false override def head: A = _head override def tail: XList[A] = _tail } object XList { def apply[A](args: A*): XList[A] = { if (args.length() == 0) { XNil } else { var k = args.length() - 1 var list: XList[A] = XNil while (k >= 0) { val it: A = args(k) list = new XCons[A](it, list) k = k - 1 } list } } } object Main { def main: Array[Int] = { val nums = XList[Int](1, 2, 3, 4, 5) val dbls = nums.map(x => x * 2) dbls.iterator.toArray } } "; Diagnostic diagnostic = new Diagnostic(); CodeGenerator codeGen = RppCompiler.Compile(program => RppCompiler.Parse(code, program), diagnostic, GetStdlibAssembly(), "Sample.dll"); if (diagnostic.HasError()) { diagnostic.Report(); } else { Debug.Assert(codeGen != null, "codeGen != null"); codeGen.Save(ApplicationType.Library); } }
private static ResolveResults SearchInClosures(string name, IEnumerable<IRppExpr> args, SymbolTable scope) { RppId closure = new RppId(name); Diagnostic diagnostic = new Diagnostic(); try { RppMember member = (RppMember) closure.Analyze(scope, diagnostic); RType closureType = member.Type.Value; if(closureType.IsObject) return null; List<RppMethodInfo> applyMethods = closureType.Methods.Where(m => m.Name == "apply").ToList(); List<RType> argTypes = args.Select(a => a.Type.Value).ToList(); IEnumerable<RppMethodInfo> candidates = OverloadQuery.Find(argTypes, applyMethods).ToList(); if (candidates.Count() > 1) { throw new Exception("Can't figure out which overload to use"); } if (!candidates.Any()) { return null; } return new ClosureResolveResults(member, candidates.First()); } catch (Exception) { return null; } }
public SemanticAnalyzerStage1(Diagnostic diagnostic) { _diagnostic = diagnostic; }
public override IRppNode Analyze(SymbolTable scope, Diagnostic diagnostic) { _classes = NodeUtils.Analyze(scope, _classes, diagnostic); return this; }
public override IRppNode Analyze(SymbolTable scope, Diagnostic diagnostic) { Expr = Expr.Analyze(scope, diagnostic) as IRppExpr; return this; }