protected override void DoEmit(EmitContext ec) { var aType = GetArithmeticType(Left, Right, Op.ToString(), ec); Left.Emit(ec); ec.EmitCast(Left.GetEvaluatedCType(ec), aType); Right.Emit(ec); ec.EmitCast(Right.GetEvaluatedCType(ec), aType); var ioff = ec.GetInstructionOffset(aType); switch (Op) { case Binop.Add: ec.Emit((OpCode)(OpCode.AddInt8 + ioff)); break; case Binop.Subtract: ec.Emit((OpCode)(OpCode.SubtractInt8 + ioff)); break; case Binop.Multiply: ec.Emit((OpCode)(OpCode.MultiplyInt8 + ioff)); break; case Binop.Divide: ec.Emit((OpCode)(OpCode.DivideInt8 + ioff)); break; case Binop.Mod: ec.Emit((OpCode)(OpCode.ModuloInt8 + ioff)); break; case Binop.BinaryAnd: ec.Emit((OpCode)(OpCode.BinaryAndInt8 + ioff)); break; case Binop.BinaryOr: ec.Emit((OpCode)(OpCode.BinaryOrInt8 + ioff)); break; case Binop.BinaryXor: ec.Emit((OpCode)(OpCode.BinaryXorInt8 + ioff)); break; case Binop.ShiftLeft: ec.Emit((OpCode)(OpCode.ShiftLeftInt8 + ioff)); break; case Binop.ShiftRight: ec.Emit((OpCode)(OpCode.ShiftRightInt8 + ioff)); break; default: throw new NotSupportedException("Unsupported binary operator '" + Op + "'"); } }
protected override void DoEmit(EmitContext ec) { if (Right is StructureExpression sexpr) { DoEmitStructureAssignment(sexpr, ec); return; } Right.Emit(ec); if (Left is VariableExpression variable) { ec.EmitCast(Right.GetEvaluatedCType(ec), Left.GetEvaluatedCType(ec)); ec.Emit(OpCode.Dup); var v = ec.ResolveVariable(variable, null); if (v.Scope == VariableScope.Global) { ec.Emit(OpCode.StoreGlobal, v.Address); } else if (v.Scope == VariableScope.Local) { ec.Emit(OpCode.StoreLocal, v.Address); } else if (v.Scope == VariableScope.Arg) { ec.Emit(OpCode.StoreArg, v.Address); } else if (v.Scope == VariableScope.Function) { ec.Emit(OpCode.Pop); ec.Report.Error(1656, $"Cannot assign to `{variable.VariableName}` because it is a function"); } else { throw new NotSupportedException("Assigning to scope '" + v.Scope + "'"); } } else if (Left.CanEmitPointer) { ec.EmitCast(Right.GetEvaluatedCType(ec), Left.GetEvaluatedCType(ec)); ec.Emit(OpCode.Dup); Left.EmitPointer(ec); ec.Emit(OpCode.StorePointer); } else { ec.Report.Error(131, "The left-hand side of an assignment must be a variable or an addressable memory location"); } }
protected override void DoEmit(EmitContext ec) { if (ReturnExpression != null) { if (ec.FunctionDecl.FunctionType.IsVoid) { ec.Report.Error(127, "A return keyword must not be followed by any expression when the function returns void"); } else { ReturnExpression.Emit(ec); ec.EmitCast(ReturnExpression.GetEvaluatedCType(ec), ec.FunctionDecl.FunctionType.ReturnType); ec.Emit(OpCode.Return); } } else { if (ec.FunctionDecl.FunctionType.IsVoid) { ec.Emit(OpCode.Return); } else { ec.Report.Error(126, "A value is required for the return statement"); } } }
protected override void DoEmit(EmitContext ec) { switch (Op) { case Unop.PreIncrement: { var ie = new AssignExpression(Right, new BinaryExpression(Right, Binop.Add, ConstantExpression.One)); ie.Emit(ec); } break; case Unop.PreDecrement: { var ie = new AssignExpression(Right, new BinaryExpression(Right, Binop.Add, ConstantExpression.NegativeOne)); ie.Emit(ec); } break; case Unop.PostIncrement: { Right.Emit(ec); var ie = new AssignExpression(Right, new BinaryExpression(Right, Binop.Add, ConstantExpression.One)); ie.Emit(ec); ec.Emit(OpCode.Pop); } break; case Unop.PostDecrement: { Right.Emit(ec); var ie = new AssignExpression(Right, new BinaryExpression(Right, Binop.Add, ConstantExpression.NegativeOne)); ie.Emit(ec); ec.Emit(OpCode.Pop); } break; default: { var aType = (CBasicType)GetEvaluatedCType(ec); Right.Emit(ec); ec.EmitCast(Right.GetEvaluatedCType(ec), aType); var ioff = ec.GetInstructionOffset(aType); switch (Op) { case Unop.None: break; case Unop.Negate: ec.Emit((OpCode)(OpCode.NegateInt8 + ioff)); break; case Unop.Not: ec.Emit((OpCode)(OpCode.NotInt8 + ioff)); break; default: throw new NotSupportedException("Unsupported unary operator '" + Op + "'"); } } break; } }
protected override void DoEmit(EmitContext ec) { var rtype = GetEvaluatedCType(ec); var itype = InnerExpression.GetEvaluatedCType(ec); InnerExpression.Emit(ec); ec.EmitCast(itype, rtype); }
protected override void DoEmit(EmitContext ec) { var argTypes = new CType[Arguments.Count]; for (var i = 0; i < Arguments.Count; i++) { argTypes[i] = Arguments[i].GetEvaluatedCType(ec); } var function = ResolveOverload(Function, argTypes, ec); var type = function.CType as CFunctionType; var numRequiredParameters = 0; if (type != null) { foreach (var p in type.Parameters) { if (p.DefaultValue.HasValue) { break; } numRequiredParameters++; } if (Arguments.Count < numRequiredParameters) { ec.Report.Error(1501, "'{0}' takes {1} arguments, {2} provided", Function, numRequiredParameters, Arguments.Count); return; } } else { //if (!Function.HasError) { ec.Report.Error(2064, "'{0}' does not evaluate to a function taking {1} arguments", Function, Arguments.Count); } return; } for (var i = 0; i < Arguments.Count; i++) { Arguments[i].Emit(ec); ec.EmitCast(argTypes[i], type.Parameters[i].ParameterType); } for (var i = Arguments.Count; i < type.Parameters.Count; i++) { var v = type.Parameters[i].DefaultValue ?? (Value)0; ec.Emit(OpCode.LoadConstant, v); } function.Emit(ec); ec.Emit(OpCode.Call, type.Parameters.Count); if (type.ReturnType.IsVoid) { ec.Emit(OpCode.LoadConstant, 0); // Expressions should leave something on the stack } }
protected override void DoEmit(EmitContext ec) { var aType = GetArithmeticType(Left, Right, Op.ToString(), ec); Left.Emit(ec); ec.EmitCast(Left.GetEvaluatedCType(ec), aType); Right.Emit(ec); ec.EmitCast(Right.GetEvaluatedCType(ec), aType); var ioff = ec.GetInstructionOffset(aType); switch (Op) { case RelationalOp.Equals: ec.Emit((OpCode)(OpCode.EqualToInt8 + ioff)); break; case RelationalOp.NotEquals: ec.Emit((OpCode)(OpCode.EqualToInt8 + ioff)); ec.Emit((OpCode)(OpCode.NotInt8 + ioff)); break; case RelationalOp.LessThan: ec.Emit((OpCode)(OpCode.LessThanInt8 + ioff)); break; case RelationalOp.LessThanOrEqual: ec.Emit((OpCode)(OpCode.GreaterThanInt8 + ioff)); ec.Emit((OpCode)(OpCode.NotInt8 + ioff)); break; case RelationalOp.GreaterThan: ec.Emit((OpCode)(OpCode.GreaterThanInt8 + ioff)); break; case RelationalOp.GreaterThanOrEqual: ec.Emit((OpCode)(OpCode.LessThanInt8 + ioff)); ec.Emit((OpCode)(OpCode.NotInt8 + ioff)); break; default: throw new NotSupportedException("Unsupported relational operator '" + Op + "'"); } }
protected override void DoEmit(EmitContext ec) { if (Right is StructureExpression sexpr) { DoEmitStructureAssignment(sexpr, ec); return; } Right.Emit(ec); if (Left is VariableExpression) { ec.EmitCast(Right.GetEvaluatedCType(ec), Left.GetEvaluatedCType(ec)); ec.Emit(OpCode.Dup); string variableName = ((VariableExpression)Left).VariableName; var v = ec.ResolveVariable(variableName, null); if (v == null) { ec.Emit(OpCode.Pop); ec.Report.Error(103, $"The name `{variableName}` does not exist in the current context."); } else if (v.Scope == VariableScope.Global) { ec.Emit(OpCode.StoreGlobal, v.Address); } else if (v.Scope == VariableScope.Local) { ec.Emit(OpCode.StoreLocal, v.Address); } else if (v.Scope == VariableScope.Arg) { ec.Emit(OpCode.StoreArg, v.Address); } else if (v.Scope == VariableScope.Function) { ec.Emit(OpCode.Pop); ec.Report.Error(1656, $"Cannot assign to `{variableName}` because it is a function"); } else { throw new NotSupportedException("Assigning to scope '" + v.Scope + "'"); } } else { ec.Emit(OpCode.Pop); ec.Report.Error(131, "The left-hand side of an assignment must be a variable"); } }