public static Prog Load2(TextWriter outputWriter, TextWriter errorWriter, IReadOnlyList <string> rootPaths, bool checkTypes) { rootPaths = rootPaths.Select(Path.GetFullPath).ToList(); var prog = new Prog(outputWriter, errorWriter, checkTypes); var modules = new List <ClassItem>(); foreach (var fp in rootPaths) { var codeFilesPaths = getAllCodeFiles(fp, prog.RemarkList); var shortest = codeFilesPaths.OrderBy(cfp => cfp.Length).First(); var numSeparators = shortest.Split('\\').Length - 2; foreach (var cfp in codeFilesPaths) { var startIndex = "C:\\".Length; var f = cfp.Substring(startIndex, cfp.Length - ".ef".Length - startIndex); var sections = f.Split('\\').Skip(numSeparators).ToList(); var es = parseFile(prog, cfp); var moduleBody = new ClassBody(es.AsClassItems(prog.RemarkList)); addMod(sections, moduleBody, modules, prog); } } var start = new FnApply(getStartQualifiedName(modules, prog.RemarkList), new FnArguments()); var seqItems = modules.Cast <SequenceItem>().Append(start).ToList(); prog.RootElement = new FnApply( new Fn(new FnParameters(), new Sequence(seqItems)), new FnArguments()); postProcess(prog, checkTypes); return(prog); }
public EfektException ParameterArgumentCountMismatch(FnApply fna, int fnParametersCount) { return(fail( fna, "Function has " + fnParametersCount + " parameters(s) and cannot be called with " + fna.Arguments.Count + " arguments(s).")); }
// TODO move to after-typing validation eventually public void ValueReturnedFromFunctionNotUsed(FnApply fna) { w(fna, "Value returned from function '" + fna.Fn.ToCodeString() + "' is not used. In '" + fna.ToCodeString() + "'"); }
private Value eval(Element se, Env <Value> env) { C.Nn(se, env); C.ReturnsNn(); switch (se) { case Declr d: if (d.Exp == null) { env.Declare(d, Void.Instance); } else { var val = eval(d.Exp, env); if (d.Exp != Void.Instance && val == Void.Instance) { throw prog.RemarkList.AttemptToAssignVoid(d.Exp); } env.Declare(d, val); } return(Void.Instance); case Assign a: var newValue = eval(a.Exp, env); if (newValue == Void.Instance) { throw prog.RemarkList.AttemptToAssignVoid(a.Exp); } switch (a.To) { case Ident ident: env.Set(ident, newValue); break; case MemberAccess ma: var obj = eval(ma.Exp, env); var o2 = obj.AsObj(ma, prog); o2.Env.Set(ma.Ident, newValue); break; default: throw new NotSupportedException(); } return(Void.Instance); case Ident i: Value vv; if (isImportContext) { vv = env.GetWithoutImports(i).Value; } else { vv = env.Get(i).Value; } if (vv == Void.Instance) { throw prog.RemarkList.AttemptToReadUninitializedVariable(i); // todo can be done in structure } return(vv); case Return r: ret = eval(r.Exp, env); if (r.Exp != Void.Instance && ret == Void.Instance) { throw prog.RemarkList.AttemptToReturnVoid(r); } return(Void.Instance); case FnApply fna: if (fna.Fn is Ident fnI && fnI.Name == "typeof") { var spec = fna.Arguments[0]; var ofS = spec.ToCodeString(); prog.OutputWriter.WriteLine(ofS); return(Void.Instance); } Exp fn; if (false) { if (fna.Fn is MemberAccess extMemAcc) { var exp2 = eval(extMemAcc.Exp, env); if (exp2 is Obj o2) { var v = o2.Env.GetFromThisEnvOnlyOrNull(extMemAcc.Ident, false); if (v != null) { fn = v.Value; goto noExtMethodApply; } } var envV = env.GetOrNull(extMemAcc.Ident); if (envV != null) { var extFn = envV.Value.AsFn(fna, prog); if (extFn.Parameters.Count == 0) { throw prog.RemarkList.ExtensionFuncHasNoParameters(extFn, extMemAcc); } var newArgs = new FnArguments(new[] { exp2 }.Concat(fna.Arguments).ToList()); var newFna = new FnApply(extFn, newArgs) { LineIndex = fna.LineIndex, ColumnIndex = fna.ColumnIndex, LineIndexEnd = fna.LineIndexEnd, ColumnIndexEnd = fna.ColumnIndexEnd, FilePath = fna.FilePath, IsBraced = fna.IsBraced, Parent = fna.Parent }; callStack.Push(new StackItem(extFn)); var res = eval(newFna, env); callStack.Pop(); return(res); } throw prog.RemarkList.VariableIsNotDeclared(extMemAcc.Ident); } } fn = eval(fna.Fn, env); noExtMethodApply: var builtin = fn as Builtin; var eArgs = new List <Exp>(); foreach (var arg in fna.Arguments) { var eArg = (Exp)eval(arg, env); if (eArg == Void.Instance) { throw prog.RemarkList.AttemptToPassVoidToFunction(arg); } eArgs.Add(eArg); } if (builtin != null) { callStack.Push(new StackItem(builtin, builtin.Name)); var res = builtin.Fn(new FnArguments(eArgs), fna); callStack.Pop(); return(res); } var fn2 = fn.AsFn(fna, prog); if (fn2.Parameters.Count != fna.Arguments.Count) { throw prog.RemarkList.ParameterArgumentCountMismatch(fna, fn2.Parameters.Count); } var paramsEnv = fn2.Env.Create(); var ix = 0; foreach (var p in fn2.Parameters) { var eArg = (Value)eArgs[ix++]; paramsEnv.Declare(p, eArg); } var fnEnv = paramsEnv.Create(); callStack.Push(new StackItem(fn2)); if (fn2.Sequence.Count == 1) { var r = evalSequenceItem(fn2.Sequence[0], fnEnv); if (ret == null) { callStack.Pop(); return(r); } var tmp = ret; ret = null; callStack.Pop(); return(tmp); } else { foreach (var bodyElement in fn2.Sequence) { evalSequenceItemFull(bodyElement, fnEnv); if (ret != null) { var tmp = ret; ret = null; callStack.Pop(); return(tmp); } } } callStack.Pop(); return(Void.Instance); case Fn f: return(new Fn(f.Parameters, f.Sequence, env).CopyInfoFrom(f)); case When w: var test = eval(w.Test, env); var testB = test.AsBool(w.Test, prog); if (w.Otherwise == null) { if (testB.Value) { eval(w.Then, env.Create()); } return(Void.Instance); } else { if (testB.Value) { return(eval(w.Then, env.Create())); } return(eval(w.Otherwise, env.Create())); } case Loop l: var loopEnv = env.Create(); while (true) { continueLoop: foreach (var e in l.Body) { evalSequenceItemFull(e, loopEnv); if (isContinue) { isContinue = false; goto continueLoop; } if (isBreak) { isBreak = false; return(Void.Instance); } if (ret != null) { return(Void.Instance); } } } case Continue _: isContinue = true; return(Void.Instance); case Break _: isBreak = true; return(Void.Instance); case ArrConstructor ae: return(new Arr(new Values(ae.Arguments.Select(e => eval(e, env)).ToList()))); case MemberAccess ma: var exp = eval(ma.Exp, env); var o = exp.AsObj(ma, prog); return(o.Env.GetFromThisEnvOnly(ma.Ident, false).Value); case New n: var objEnv = env.Create(); // todo create foreach (var v in n.Body) { eval(v, objEnv); } return(new Obj(n.Body, objEnv) { Parent = n.Parent }); case Value ve: return(ve); case Sequence seq: var scopeEnv = env.Create(); if (seq.Count == 1) { return(eval(seq.First(), scopeEnv)); } foreach (var item in seq) { evalSequenceItemFull(item, scopeEnv); if (ret != null) { return(Void.Instance); } } return(Void.Instance); case Toss ts: var exVal = eval(ts.Exception, env); throw prog.RemarkList.ProgramException(exVal, ts, callStack.ToList()); case Attempt att: try { return(eval(att.Body, env)); } catch (EfektProgramException ex) { if (att.Grab != null) { var grabEnv = env.Create(); grabEnv.Declare(new Let(new Ident("exception", TokenType.Ident), Void.Instance), ex.Value); eval(att.Grab, grabEnv); } // todo else rethrow? return(Void.Instance); } finally { if (att.AtLast != null) { eval(att.AtLast, env); } } case Import imp: isImportContext = true; var modImpEl = eval(imp.QualifiedIdent, env); isImportContext = false; var modImp = modImpEl.AsObj(imp, prog); env.AddImport(imp.QualifiedIdent, modImp.Env, (Declr)modImp.Parent); return(Void.Instance); default: throw new NotSupportedException(); } }