// Assignment:: VAR? ident := value // If ident does not exist, creates a typed catalog entry (using return type if Funval) // Sets initial value, or updates but only if was VAR and same type public AstStatement Assignment(string ident, AstValue value, string varopt) { if (Symbols.CanDefGlobal(ident)) { if (value is AstFunval) { var cvalue = (value as AstFunval).Value; Symbols.AddDeffun(ident, cvalue.DataType, cvalue.Lookup.Columns, cvalue.Accums, varopt != null); } else { Symbols.AddVariable(ident, value.DataType, SymKinds.CATVAR, varopt != null); } Symbols.AddCatalog(Symbols.FindIdent(ident)); } else { var sym = FindCatVar(ident); if (sym == null || sym.IsCallable || !sym.Mutable) { Parser.ParseError("cannot assign to '{0}'", sym.Name); } if (sym.DataType != value.DataType) { Parser.ParseError("type mismatch: '{0}'", sym.Name); } } return(GenFunCall(FindFunc(SymNames.Assign), Args(Text(ident), value))); }
// name, type and source of a single VAR declaration, can be // a) VAR ident : type // b) VAR ident [: typewithheading] (source) public AstStatement VarDecl(string ident, AstType type, AstLiteral source) { var what = ident; // reserved for future use var isimport = (source != null); var datatype = (type == null) ? null : isimport?Types.Relof(type.DataType) : type.DataType; if (isimport && datatype == null) { if (type != null) { Parser.ParseError($"type with heading required for '{ident}'"); } datatype = Cat.GetRelvarType(source.Value.ToString(), what); // peek the file if (datatype == null) { Parser.ParseError("cannot find '{0}' as '{1}'", ident, source); } } Symbols.AddVariable(ident, datatype, SymKinds.CATVAR, true); Symbols.AddCatalog(Symbols.FindIdent(ident)); return((isimport) ? GenFunCall(FindFunc(SymNames.Import), Args(source, Text(ident), Text(what), Text(Parser.Cat.SourcePath))) : GenFunCall(FindFunc(SymNames.Assign), Args(Text(ident), LitValue(datatype.DefaultValue())))); }
public AstTypedef UserType(string ident, AstField[] fields) { var ff = fields.Select(a => DataColumn.Create(a.Name, a.DataType)).ToArray(); var ut = DataTypeUser.Get(ident, ff); Symbols.AddUserType(ident, ut); Symbols.AddCatalog(Symbols.FindIdent(ident)); return(new AstUserType { DataType = DataTypes.Void }); }
// finalise function definition, from basic definition previously created // set or check return type // null body just defines type // Note: null arguments means argless (lazy) rather than deffun // BUG: a persistent function must not reference a non-persistent global public AstStatement Deffun(string ident, AstType rettype, IList <AstField> arguments, AstBodyStatement body) { var op = FindDefFunc(ident); var callinfo = op.CallInfo; if (callinfo.ReturnType == DataTypes.Unknown) { callinfo.ReturnType = body.DataType; } else if (callinfo.ReturnType != body.DataType) { Parser.ParseError($"{ident} return type mismatch"); } if (op.DataType == DataTypes.Unknown) { if (arguments == null) { op.DataType = callinfo.ReturnType; } } else if (op.DataType != callinfo.ReturnType) { Parser.ParseError("body does not match declared type"); } // assume top overload is the one being defined //op.callinfo.ReturnType = op.DataType; callinfo.AccumCount = body.AccumCount; callinfo.HasWin = body.HasWin; // symbol is foldable if all overloads are foldable // FIX: put this test where it's used var foldable = (callinfo.NumArgs == 2 && arguments[0].DataType == callinfo.ReturnType && arguments[1].DataType == callinfo.ReturnType) && (callinfo.OverLoad == null || op.IsFoldable); if (foldable && !op.IsFoldable) { op.Foldable = FoldableFlags.ANY; } Symbols.AddCatalog(op); // assemble node var code = Code(body.Statement as AstValue, Headingof(arguments), callinfo.Name, true, body.AccumCount, body.HasWin); return(GenFunCall(FindFunc(SymNames.Defer), Args(code))); }