public override Expression ResolveNamesAndCullUnusedCode(PastelCompiler compiler) { this.Expression = this.Expression.ResolveNamesAndCullUnusedCode(compiler); if (this.Expression is InlineConstant) { InlineConstant ic = (InlineConstant)this.Expression; if (this.FirstToken.Value == "!" && ic.Value is bool) { return(new InlineConstant(PType.BOOL, this.FirstToken, !((bool)ic.Value))); } if (this.FirstToken.Value == "-") { if (ic.Value is int) { return(new InlineConstant(PType.INT, this.FirstToken, -(int)ic.Value)); } if (ic.Value is double) { return(new InlineConstant(PType.DOUBLE, this.FirstToken, -(double)ic.Value)); } } throw new ParserException(this.OpToken, "The op '" + this.OpToken.Value + "' is not valid on this type of expression."); } return(this); }
internal Expression MaybeImmediatelyResolve(PastelParser parser) { if (this.Root is CompileTimeFunctionReference) { CompileTimeFunctionReference constFunc = (CompileTimeFunctionReference)this.Root; InlineConstant argName = (InlineConstant)this.Args[0]; switch (constFunc.NameToken.Value) { case "ext_boolean": return(new InlineConstant( PType.BOOL, this.FirstToken, parser.GetParseTimeBooleanConstant(argName.Value.ToString()))); case "ext_integer": return(new InlineConstant( PType.INT, this.FirstToken, parser.GetParseTimeIntegerConstant(argName.Value.ToString()))); default: return(this); } } return(this); }
internal override InlineConstant DoConstantResolution(HashSet <string> cycleDetection, PastelCompiler compiler) { for (int i = 0; i < this.Expressions.Length; ++i) { this.Expressions[i] = this.Expressions[i].DoConstantResolution(cycleDetection, compiler); } InlineConstant current = (InlineConstant)this.Expressions[0]; for (int i = 1; i < this.Expressions.Length; ++i) { InlineConstant next = (InlineConstant)this.Expressions[i]; string lookup = current.Type.RootValue + this.Ops[i - 1].Value + next.Type.RootValue; switch (lookup) { case "int+int": current = new InlineConstant(PType.INT, current.FirstToken, (int)current.Value + (int)next.Value); break; case "int-int": current = new InlineConstant(PType.INT, current.FirstToken, (int)current.Value - (int)next.Value); break; case "int*int": current = new InlineConstant(PType.INT, current.FirstToken, (int)current.Value * (int)next.Value); break; default: throw new NotImplementedException(); } } return(current); }
public EnumDefinition(Token enumToken, Token nameToken, IList <Token> valueTokens, IList <Expression> valueExpressions) { this.FirstToken = enumToken; this.NameToken = nameToken; this.ValueTokens = valueTokens.ToArray(); this.ValuesByName = new Dictionary <string, Expression>(); int length = this.ValueTokens.Length; int highestValue = 0; bool highestSet = false; List <string> autoAssignMe = new List <string>(); for (int i = 0; i < length; ++i) { string name = this.ValueTokens[i].Value; if (this.ValuesByName.ContainsKey(name)) { throw new ParserException(this.FirstToken, "The enum '" + this.NameToken.Value + "' has multiple definitions of '" + name + "'"); } Expression expression = valueExpressions[i]; if (expression == null) { autoAssignMe.Add(name); } else { this.ValuesByName[name] = expression; if (expression is InlineConstant) { InlineConstant ic = (InlineConstant)expression; if (ic.Value is int) { if (!highestSet || (int)ic.Value > highestValue) { highestValue = (int)ic.Value; highestSet = true; } } else { throw new ParserException(expression.FirstToken, "Only integers are allowed as enum values."); } } else { this.UnresolvedValues.Add(name); } } } // anything that doesn't have a value assigned to it, auto-assign incrementally from the highest value provided. foreach (string name in autoAssignMe) { this.ValuesByName[name] = new InlineConstant(PType.INT, this.FirstToken, highestValue++); } }
internal override Expression ResolveType(VariableScope varScope, PastelCompiler compiler) { this.Root = this.Root.ResolveType(varScope, compiler); this.Index = this.Index.ResolveType(varScope, compiler); PType rootType = this.Root.ResolvedType; PType indexType = this.Index.ResolvedType; bool badIndex = false; if (rootType.RootValue == "List" || rootType.RootValue == "Array") { badIndex = !indexType.IsIdentical(PType.INT); this.ResolvedType = rootType.Generics[0]; } else if (rootType.RootValue == "Dictionary") { badIndex = !indexType.IsIdentical(rootType.Generics[0]); this.ResolvedType = rootType.Generics[1]; } else if (rootType.RootValue == "string") { badIndex = !indexType.IsIdentical(PType.INT); this.ResolvedType = PType.CHAR; if (this.Root is InlineConstant && this.Index is InlineConstant) { string c = ((string)((InlineConstant)this.Root).Value)[(int)((InlineConstant)this.Index).Value].ToString(); InlineConstant newValue = new InlineConstant(PType.CHAR, this.FirstToken, c); newValue.ResolveType(varScope, compiler); return(newValue); } } else { badIndex = true; } if (badIndex) { throw new ParserException(this.BracketToken, "Cannot index into a " + rootType + " with a " + indexType + "."); } return(this); }
public override Expression ResolveNamesAndCullUnusedCode(PastelCompiler compiler) { string name = this.Name; InlineConstant constantValue = compiler.GetConstantDefinition(name); if (constantValue != null) { return(constantValue.CloneWithNewToken(this.FirstToken)); } if (name == "Core") { return(new CoreNamespaceReference(this.FirstToken, this.Owner)); } if (name == "Extension") { return(new ExtensibleNamespaceReference(this.FirstToken, this.Owner)); } FunctionDefinition functionDefinition = compiler.GetFunctionDefinition(name); if (functionDefinition != null) { return(new FunctionReference(this.FirstToken, functionDefinition, this.Owner)); } EnumDefinition enumDefinition = compiler.GetEnumDefinition(name); if (enumDefinition != null) { return(new EnumReference(this.FirstToken, enumDefinition, this.Owner)); } if (compiler.IncludedScopeNamespacesToIndex.ContainsKey(name)) { int index = compiler.IncludedScopeNamespacesToIndex[name]; PastelCompiler referencedScope = compiler.IncludedScopes[index]; return(new DependencyNamespaceReference(this.FirstToken, referencedScope, this.Owner)); } return(this); }
public override Expression ResolveNamesAndCullUnusedCode(PastelCompiler compiler) { string name = this.Name; InlineConstant constantValue = compiler.GetConstantDefinition(name); if (constantValue != null) { return(constantValue.CloneWithNewToken(this.FirstToken)); } FunctionDefinition functionDefinition = compiler.GetFunctionDefinitionAndMaybeQueueForResolution(name); if (functionDefinition != null) { return(new FunctionReference(this.FirstToken, functionDefinition)); } return(this); }
public override Expression ResolveNamesAndCullUnusedCode(PastelCompiler compiler) { this.Root = this.Root.ResolveNamesAndCullUnusedCode(compiler); Variable varRoot = this.Root as Variable; if (varRoot != null) { string rootName = varRoot.Name; if (rootName == "Core") { NativeFunction nativeFunction = this.GetNativeCoreFunction(this.FieldName.Value); switch (nativeFunction) { case NativeFunction.FLOAT_BUFFER_16: case NativeFunction.INT_BUFFER_16: case NativeFunction.STRING_BUFFER_16: return(new NativeFunctionInvocation(this.FirstToken, nativeFunction, new Expression[0])); default: return(new NativeFunctionReference(this.FirstToken, nativeFunction)); } } EnumDefinition enumDef = compiler.GetEnumDefinition(rootName); if (enumDef != null) { InlineConstant enumValue = enumDef.GetValue(this.FieldName); return(enumValue.CloneWithNewToken(this.FirstToken)); } } else if (this.Root is EnumReference) { EnumDefinition enumDef = ((EnumReference)this.Root).EnumDef; InlineConstant enumValue = enumDef.GetValue(this.FieldName); return(enumValue); } return(this); }
internal override Executable ResolveWithTypeContext(PastelCompiler compiler) { this.Condition = this.Condition.ResolveWithTypeContext(compiler); HashSet <int> values = new HashSet <int>(); for (int i = 0; i < this.Chunks.Length; ++i) { SwitchChunk chunk = this.Chunks[i]; for (int j = 0; j < chunk.Cases.Length; ++j) { if (chunk.Cases[j] != null) { chunk.Cases[j] = chunk.Cases[j].ResolveWithTypeContext(compiler); InlineConstant ic = chunk.Cases[j] as InlineConstant; if (ic == null) { throw new ParserException(chunk.Cases[j].FirstToken, "Only constants may be used as switch cases."); } int value; if (ic.ResolvedType.RootValue == "char") { value = (char)ic.Value; } else { value = (int)ic.Value; } if (values.Contains(value)) { throw new ParserException(chunk.Cases[j].FirstToken, "This cases appears multiple times."); } values.Add(value); } } Executable.ResolveWithTypeContext(compiler, chunk.Code); } return(this); }
internal void DoConstantResolutions(HashSet <string> cycleDetection, PastelCompiler compiler) { string prefix = this.NameToken.Value + "."; foreach (string name in this.UnresolvedValues) { string cycleKey = prefix + name; if (cycleDetection.Contains(cycleKey)) { throw new ParserException(this.FirstToken, "This enum has a cycle in its value declarations in '" + name + "'"); } cycleDetection.Add(cycleKey); InlineConstant ic = this.ValuesByName[cycleKey].DoConstantResolution(cycleDetection, compiler); if (!(ic.Value is int)) { throw new ParserException(ic.FirstToken, "Enum values must resolve into integers. This does not."); } this.ValuesByName[cycleKey] = ic; cycleDetection.Remove(cycleKey); } }
public override Expression ResolveNamesAndCullUnusedCode(PastelCompiler compiler) { this.Root = this.Root.ResolveNamesAndCullUnusedCode(compiler); if (this.Root is EnumReference) { InlineConstant enumValue = ((EnumReference)this.Root).EnumDef.GetValue(this.FieldName); return(enumValue.CloneWithNewToken(this.FirstToken)); } if (this.Root is DependencyNamespaceReference) { PastelCompiler dependencyScope = ((DependencyNamespaceReference)this.Root).Scope; string field = this.FieldName.Value; FunctionDefinition funcDef = dependencyScope.GetFunctionDefinition(field); if (funcDef != null) { return(new FunctionReference(this.FirstToken, funcDef, this.Owner)); } EnumDefinition enumDef = dependencyScope.GetEnumDefinition(field); if (enumDef != null) { return(new EnumReference(this.FirstToken, enumDef, this.Owner)); } InlineConstant constValue = dependencyScope.GetConstantDefinition(field); if (constValue != null) { return(constValue.CloneWithNewTokenAndOwner(this.FirstToken, this.Owner)); } throw new ParserException(this.FieldName, "The namespace '" + ((DependencyNamespaceReference)this.Root).FirstToken.Value + "' does not have a member called '" + field + "'"); } if (this.Root is CoreNamespaceReference) { CoreFunction coreFunction = this.GetCoreFunction(this.FieldName.Value); switch (coreFunction) { case CoreFunction.FLOAT_BUFFER_16: case CoreFunction.INT_BUFFER_16: case CoreFunction.STRING_BUFFER_16: return(new CoreFunctionInvocation(this.FirstToken, coreFunction, new Expression[0], this.Owner)); default: return(new CoreFunctionReference(this.FirstToken, coreFunction, this.Owner)); } } if (this.Root is ExtensibleNamespaceReference) { string name = this.FieldName.Value; return(new ExtensibleFunctionReference(this.FirstToken, name, this.Owner)); } if (this.Root is EnumReference) { EnumDefinition enumDef = ((EnumReference)this.Root).EnumDef; InlineConstant enumValue = enumDef.GetValue(this.FieldName); return(enumValue); } return(this); }
internal override Expression ResolveWithTypeContext(PastelCompiler compiler) { for (int i = 0; i < this.Expressions.Length; ++i) { this.Expressions[i] = this.Expressions[i].ResolveWithTypeContext(compiler); } InlineConstant left = this.Expressions[0] as InlineConstant; InlineConstant right = this.Expressions[1] as InlineConstant; while (left != null && right != null) { object leftValue = left.Value; object rightValue = right.Value; string lookup = left.ResolvedType.RootValue + this.Ops[0].Value + right.ResolvedType.RootValue; switch (lookup) { case "int+int": this.Expressions[0] = CreateInteger(left.FirstToken, (int)leftValue + (int)rightValue); break; case "int-int": this.Expressions[0] = CreateInteger(left.FirstToken, (int)leftValue - (int)rightValue); break; case "int*int": this.Expressions[0] = CreateInteger(left.FirstToken, (int)leftValue * (int)rightValue); break; case "int/int": this.Expressions[0] = CreateInteger(left.FirstToken, (int)leftValue / (int)rightValue); break; case "int+double": this.Expressions[0] = CreateFloat(left.FirstToken, (int)leftValue + (double)rightValue); break; case "int-double": this.Expressions[0] = CreateFloat(left.FirstToken, (int)leftValue - (double)rightValue); break; case "int*double": this.Expressions[0] = CreateFloat(left.FirstToken, (int)leftValue * (double)rightValue); break; case "int/double": this.Expressions[0] = CreateFloat(left.FirstToken, (int)leftValue / (double)rightValue); break; case "double+int": this.Expressions[0] = CreateFloat(left.FirstToken, (double)leftValue + (int)rightValue); break; case "double-int": this.Expressions[0] = CreateFloat(left.FirstToken, (double)leftValue - (int)rightValue); break; case "double*int": this.Expressions[0] = CreateFloat(left.FirstToken, (double)leftValue * (int)rightValue); break; case "double/int": this.Expressions[0] = CreateFloat(left.FirstToken, (double)leftValue / (int)rightValue); break; case "double+double": this.Expressions[0] = CreateFloat(left.FirstToken, (double)leftValue + (double)rightValue); break; case "double-double": this.Expressions[0] = CreateFloat(left.FirstToken, (double)leftValue - (double)rightValue); break; case "double*double": this.Expressions[0] = CreateFloat(left.FirstToken, (double)leftValue * (double)rightValue); break; case "double/double": this.Expressions[0] = CreateFloat(left.FirstToken, (double)leftValue / (double)rightValue); break; case "bool&&bool": this.Expressions[0] = CreateBoolean(left.FirstToken, (bool)leftValue && (bool)rightValue); break; case "bool||bool": this.Expressions[0] = CreateBoolean(left.FirstToken, (bool)leftValue || (bool)rightValue); break; default: if (this.Ops[0].Value == "%") { throw new NotImplementedException("Remember when you implement this to prevent negatives."); } throw new ParserException(this.Ops[0], "The operator is not defined for these two constants."); } List <Expression> expressions = new List <Expression>(this.Expressions); expressions.RemoveAt(1); // I know, I know... this.Expressions = expressions.ToArray(); if (this.Expressions.Length == 1) { return(this.Expressions[0]); } List <Token> ops = new List <Token>(this.Ops); ops.RemoveAt(0); this.Ops = ops.ToArray(); left = this.Expressions[0] as InlineConstant; right = this.Expressions[1] as InlineConstant; } return(this); }
internal override Expression ResolveWithTypeContext(PastelCompiler compiler) { for (int i = 0; i < this.Expressions.Length; ++i) { this.Expressions[i] = this.Expressions[i].ResolveWithTypeContext(compiler); } InlineConstant left = this.Expressions[0] as InlineConstant; InlineConstant right = this.Expressions[1] as InlineConstant; while (left != null && right != null) { object leftValue = left.Value; object rightValue = right.Value; string lookup = left.ResolvedType.RootValue + this.Ops[0].Value + right.ResolvedType.RootValue; switch (lookup) { case "int+int": this.Expressions[0] = CreateInteger(left.FirstToken, (int)leftValue + (int)rightValue); break; case "int-int": this.Expressions[0] = CreateInteger(left.FirstToken, (int)leftValue - (int)rightValue); break; case "int*int": this.Expressions[0] = CreateInteger(left.FirstToken, (int)leftValue * (int)rightValue); break; case "int/int": this.Expressions[0] = CreateInteger(left.FirstToken, (int)leftValue / (int)rightValue); break; case "int+double": this.Expressions[0] = CreateFloat(left.FirstToken, (int)leftValue + (double)rightValue); break; case "int-double": this.Expressions[0] = CreateFloat(left.FirstToken, (int)leftValue - (double)rightValue); break; case "int*double": this.Expressions[0] = CreateFloat(left.FirstToken, (int)leftValue * (double)rightValue); break; case "int/double": this.Expressions[0] = CreateFloat(left.FirstToken, (int)leftValue / (double)rightValue); break; case "double+int": this.Expressions[0] = CreateFloat(left.FirstToken, (double)leftValue + (int)rightValue); break; case "double-int": this.Expressions[0] = CreateFloat(left.FirstToken, (double)leftValue - (int)rightValue); break; case "double*int": this.Expressions[0] = CreateFloat(left.FirstToken, (double)leftValue * (int)rightValue); break; case "double/int": this.Expressions[0] = CreateFloat(left.FirstToken, (double)leftValue / (int)rightValue); break; case "double+double": this.Expressions[0] = CreateFloat(left.FirstToken, (double)leftValue + (double)rightValue); break; case "double-double": this.Expressions[0] = CreateFloat(left.FirstToken, (double)leftValue - (double)rightValue); break; case "double*double": this.Expressions[0] = CreateFloat(left.FirstToken, (double)leftValue * (double)rightValue); break; case "double/double": this.Expressions[0] = CreateFloat(left.FirstToken, (double)leftValue / (double)rightValue); break; case "bool&&bool": this.Expressions[0] = CreateBoolean(left.FirstToken, (bool)leftValue && (bool)rightValue); break; case "bool||bool": this.Expressions[0] = CreateBoolean(left.FirstToken, (bool)leftValue || (bool)rightValue); break; default: if (this.Ops[0].Value == "%") { throw new NotImplementedException("Remember when you implement this to prevent negatives."); } throw new ParserException(this.Ops[0], "The operator is not defined for these two constants."); } List <Expression> expressions = new List <Expression>(this.Expressions); expressions.RemoveAt(1); // I know, I know... this.Expressions = expressions.ToArray(); if (this.Expressions.Length == 1) { return(this.Expressions[0]); } List <Token> ops = new List <Token>(this.Ops); ops.RemoveAt(0); this.Ops = ops.ToArray(); left = this.Expressions[0] as InlineConstant; right = this.Expressions[1] as InlineConstant; } // TODO(pastel-split): This is just a quick and dirty short-circuit logic for && and || // Do full logic later. Currently this is causing problems in specific snippets in Crayon libraries. string opValue = this.Ops[0].Value; if (left != null) { if (opValue == "&&" && left.Value is bool) { return((bool)left.Value ? (Expression)this : left); } if (opValue == "||" && left.Value is bool) { return((bool)left.Value ? left : (Expression)this); } } return(this); }