void Write(CiClass klass, CiMethod method) { if (method.CallType == CiCallType.Abstract) { return; } WriteLine(); WriteDoc(method); Write(klass.Name); Write('.'); if (method.CallType != CiCallType.Static) { Write("prototype."); } WriteCamelCase(method.Name); Write(" = function("); bool first = true; foreach (CiVar param in method.Parameters) { if (!first) { Write(", "); } first = false; Write(param.Name); if (param.Value != null) { Write(" = "); param.Value.Accept(this, CiPriority.Statement); } } Write(')'); WriteBody(method); }
static void MarkInternal(CiMethod method) { if (method.Visibility == CiVisibility.Private && method.CalledBy.Any(caller => caller.Class != method.Class)) { method.Visibility = CiVisibility.Internal; } }
void WritePyDoc(CiMethod method) { if (method.Documentation == null) { return; } StartDoc(method.Documentation); bool first = true; foreach (CiVar param in method.Parameters) { if (param.Documentation != null) { if (first) { WriteLine(); WriteLine(); first = false; } Write(":param "); WriteName(param); Write(": "); Write(param.Documentation.Summary, false); WriteLine(); } } WriteLine("\"\"\""); }
void ICiSymbolVisitor.Visit(CiMethod method) { WriteLine(); Write(method.Documentation); bool paramsStarted = false; foreach (CiParam param in method.Signature.Params) { if (param.Documentation != null) { if (!paramsStarted) { WriteLine("/// Params:"); paramsStarted = true; } Write("/// "); WriteVarName(param.Name); Write(" = "); Write(param.Documentation.Summary); WriteLine(); } } Write(method.Visibility); switch (method.CallType) { case CiCallType.Static: Write("static "); break; case CiCallType.Normal: if (method.Visibility != CiVisibility.Private) Write("final "); break; case CiCallType.Abstract: Write("abstract "); break; case CiCallType.Virtual: break; case CiCallType.Override: Write("override "); break; } WriteSignature(method.Signature); if (method.CallType == CiCallType.Abstract) WriteLine(";"); else { WriteLine(); Write(method.Body); } }
void ICiSymbolVisitor.Visit(CiMethod method) { WriteLine(); WriteDoc(method); WriteVisibility(method); switch (method.CallType) { case CiCallType.Static: Write("static "); break; case CiCallType.Normal: if (method.Visibility != CiVisibility.Private) { Write("final "); } break; case CiCallType.Override: Write("override "); break; default: break; } Write("function "); WriteCamelCase(method.Name); Write('('); bool first = true; foreach (CiParam param in method.Signature.Params) { if (first) { first = false; } else { Write(", "); } Write(param.Name); Write(param.Type); } Write(")"); Write(method.Signature.ReturnType); WriteLine(); OpenBlock(); if (method.CallType == CiCallType.Abstract) { WriteLine("throw \"Abstract method called\";"); } else { ICiStatement[] statements = method.Body.Statements; Write(statements); if (method.Signature.ReturnType != CiType.Void && statements.Length > 0) { CiFor lastLoop = statements[statements.Length - 1] as CiFor; if (lastLoop != null && lastLoop.Cond == null) { WriteLine("throw \"Unreachable\";"); } } } CloseBlock(); }
protected static bool IsStringSubstring(CiExpr expr, out bool cast, out CiExpr ptr, out CiExpr offset, out CiExpr length) { if (expr is CiCallExpr call) { CiMethod method = (CiMethod)call.Method.Symbol; CiExpr[] args = call.Arguments; if (method == CiSystem.StringSubstring && args.Length == 2) { cast = false; ptr = call.Method.Left; offset = args[0]; length = args[1]; return(true); } if (method == CiSystem.UTF8GetString) { cast = true; ptr = args[0]; offset = args[1]; length = args[2]; return(true); } } cast = false; ptr = null; offset = null; length = null; return(false); }
void Write(CiMethod method) { if (method.CallType == CiCallType.Abstract) { return; } WriteLine(); Write(method.Class.Name); Write('.'); if (method.CallType != CiCallType.Static) { Write("prototype."); } WriteCamelCase(method.Name); Write(" = function("); bool first = true; foreach (CiParam param in method.Signature.Params) { if (first) { first = false; } else { Write(", "); } Write(param.Name); } Write(") "); Write(method.Body); }
void WriteConstructor(CiClass klass) { // TODO: skip constructor if static methods only? if (klass.Visibility == CiVisibility.Public) { Write("=head2 C<$"); WriteLowercase(klass.Name); Write(" = "); Write(this.Package); Write(klass.Name); WriteLine("-E<gt>new()>"); WriteLine(); if (klass.Constructor != null) { Write(klass.Constructor.Documentation); } WriteLine("=cut"); WriteLine(); } IEnumerable <CiField> classStorageFields = klass.Members .OfType <CiField>().Where(field => field.Type is CiClassStorageType); if (klass.Constructor == null && klass.BaseClass != null && !classStorageFields.Any()) { // base constructor does the job return; } Write("sub new($) "); OpenBlock(); if (klass.BaseClass != null) { WriteLine("my $self = shift()->SUPER::new();"); } else { WriteLine("my $self = bless {}, shift;"); } foreach (CiField field in classStorageFields) { Write("$self->{"); WriteLowercaseWithUnderscores(field.Name); Write("} = "); WriteNew(field.Type); WriteLine(";"); } if (klass.Constructor != null) { this.CurrentMethod = klass.Constructor; Write(klass.Constructor.Body.Statements); this.CurrentMethod = null; } WriteLine("return $self;"); // TODO: premature returns CloseBlock(); WriteLine(); }
static void MarkDead(CiMethod method) { if (method.Visibility == CiVisibility.Private && method.CallType != CiCallType.Override && method.CalledBy.Count == 0) { method.Visibility = CiVisibility.Dead; foreach (CiMethod called in method.Calls) { called.CalledBy.Remove(method); MarkDead(called); } } }
static void MarkThrows(CiMethod method) { if (method.Throws) { return; } method.Throws = true; method.ErrorReturnValue = GetErrorValue(method.Signature.ReturnType); foreach (CiMethod calledBy in method.CalledBy) { MarkThrows(calledBy); } }
void ICiSymbolVisitor.Visit(CiMethod method) { WriteLine(); Write(method.Documentation); bool paramsStarted = false; foreach (CiParam param in method.Signature.Params) { if (param.Documentation != null) { if (!paramsStarted) { WriteLine("/// Params:"); paramsStarted = true; } Write("/// "); WriteVarName(param.Name); Write(" = "); Write(param.Documentation.Summary); WriteLine(); } } Write(method.Visibility); switch (method.CallType) { case CiCallType.Static: Write("static "); break; case CiCallType.Normal: if (method.Visibility != CiVisibility.Private) { Write("final "); } break; case CiCallType.Abstract: Write("abstract "); break; case CiCallType.Virtual: break; case CiCallType.Override: Write("override "); break; } WriteSignature(method.Signature, method.Name); if (method.CallType == CiCallType.Abstract) { WriteLine(";"); } else { WriteLine(); Write(method.Body); } }
protected override void WriteCall(CiExpr obj, CiMethod method, CiExpr[] args, CiPriority parent) { if (obj == null) { WriteLocalName(method, CiPriority.Primary); WriteArgsInParentheses(method, args); } else if (method == CiSystem.StringSubstring) { obj.Accept(this, CiPriority.Primary); Write(".substring("); args[0].Accept(this, CiPriority.Argument); if (args.Length == 2) { Write(", "); WriteAdd(args[0], args[1]); // TODO: side effect } Write(')'); } else if (obj.Type is CiArrayType && method.Name == "CopyTo") { AddLibrary(GenJsMethod.CopyArray, "copyArray : function(sa, soffset, da, doffset, length)", "if (typeof(sa.subarray) == \"function\" && typeof(da.set) == \"function\")", "\tda.set(sa.subarray(soffset, soffset + length), doffset);", "else", "\tfor (let i = 0; i < length; i++)", "\t\tda[doffset + i] = sa[soffset + i];"); Write("Ci.copyArray("); obj.Accept(this, CiPriority.Argument); Write(", "); WriteArgs(method, args); Write(')'); } else if (obj.Type is CiArrayType array && method.Name == "Fill") { obj.Accept(this, CiPriority.Primary); Write(".fill("); args[0].Accept(this, CiPriority.Argument); if (args.Length == 3) { Write(", "); WriteStartEnd(args[1], args[2]); } Write(')'); }
protected void WriteArgs(CiMethod method, CiExpr[] args) { int i = 0; foreach (CiVar param in method.Parameters) { if (i >= args.Length) { break; } if (i > 0) { Write(", "); } WriteCoerced(param.Type, args[i++], CiPriority.Statement); } }
static bool IsOverrideOf(CiMethod derived, CiMethod baseMethod) { if (derived == null || baseMethod == null) { return(false); } if (derived.CallType != CiCallType.Override && derived.CallType != CiCallType.Sealed) { return(false); } if (baseMethod.CallType == CiCallType.Static || baseMethod.CallType == CiCallType.Normal) { return(false); } // TODO: check parameter and return type baseMethod.Calls.Add(derived); return(true); }
protected void WriteDoc(CiMethod method) { if (method.Documentation != null) { WriteDontClose(method.Documentation); foreach (CiParam param in method.Signature.Params) { if (param.Documentation != null) { Write(" * @param "); Write(param.Name); Write(' '); Write(param.Documentation.Summary); WriteLine(); } } WriteLine(" */"); } }
protected void WriteMathCall(CiMethod method, CiExpr[] args) { if (method.Name == "Ceiling") { Write("ceil"); } else if (method.Name == "FusedMultiplyAdd") { Write("fma"); } else if (method.Name == "Truncate") { Write("trunc"); } else { WriteLowercase(method.Name); } WriteArgsInParentheses(method, args); }
protected void WriteDoc(CiMethod method) { if (method.Documentation == null) { return; } StartDoc(method.Documentation); WriteSelfDoc(method); foreach (CiVar param in method.Parameters) { if (param.Documentation != null) { Write(" * @param "); Write(param.Name); Write(' '); Write(param.Documentation.Summary); WriteLine(); } } WriteLine(" */"); }
void WriteStringMethod(CiExpr obj, string name, CiMethod method, CiExpr[] args) { obj.Accept(this, CiPriority.Primary); if (obj is CiLiteral) { this.UsingStringViewLiterals = true; Write("sv"); } Write('.'); Write(name); if (IsOneAsciiString(args[0], out char c)) { Write('('); WriteCharLiteral(c); Write(')'); } else { WriteArgsInParentheses(method, args); } }
void ICiSymbolVisitor.Visit(CiMethod method) { WriteLine(); Write(method.Documentation); foreach (CiParam param in method.Signature.Params) { if (param.Documentation != null) { Write("/// <param name=\""); Write(param.Name); Write("\">"); Write(param.Documentation.Summary); WriteLine("</param>"); } } Write(method.Visibility); switch (method.CallType) { case CiCallType.Static: Write("static "); break; case CiCallType.Normal: break; case CiCallType.Abstract: Write("abstract "); break; case CiCallType.Virtual: Write("virtual "); break; case CiCallType.Override: Write("override "); break; } WriteSignature(method.Signature); if (method.CallType == CiCallType.Abstract) { WriteLine(";"); } else { WriteLine(); Write(method.Body); } }
void ICiSymbolVisitor.Visit(CiMethod method) { WriteLine(); WriteDoc(method); if (method.CallType == CiCallType.Override) { WriteLine("@Override"); } Write(method.Visibility); switch (method.CallType) { case CiCallType.Static: Write("static "); break; case CiCallType.Normal: if (method.Visibility != CiVisibility.Private) { Write("final "); } break; case CiCallType.Abstract: Write("abstract "); break; default: break; } WriteSignature(method.Signature, method.Name); if (method.Throws) { Write(" throws Exception"); } if (method.CallType == CiCallType.Abstract) { WriteLine(";"); } else { WriteLine(); Write(method.Body); } }
protected override void WriteCall(CiExpr obj, CiMethod method, CiExpr[] args, CiPriority parent) { if (obj == null) { WriteCCall(null, method, args); } else if (obj.IsReferenceTo(CiSystem.MathClass)) { WriteMathCall(method, args); } else if (method == CiSystem.ConsoleWrite) { WriteConsoleWrite(args, false); } else if (method == CiSystem.ConsoleWriteLine) { WriteConsoleWrite(args, true); } else { WriteCCall(obj, method, args); } }
protected void WriteMathCall(CiMethod method, CiExpr[] args) { if (method == CiSystem.MathCeiling) { Write("ceil"); } else if (method == CiSystem.MathFusedMultiplyAdd) { Write("fma"); } else if (method == CiSystem.MathIsInfinity) { Write("isinf"); } else if (method == CiSystem.MathTruncate) { Write("trunc"); } else { WriteLowercase(method.Name); } WriteArgsInParentheses(method, args); }
CiMethod ParseConstructor() { OpenScope(); CiMethod method = new CiMethod( CiType.Void, "<constructor>") { Class = this.CurrentClass, CallType = CiCallType.Normal, This = CreateThis() }; this.CurrentMethod = method; method.Body = ParseBlock(); CloseScope(); this.CurrentMethod = null; return method; }
void ParseMethod(CiMethod method) { this.CurrentMethod = method; OpenScope(); if (method.CallType != CiCallType.Static) method.This = CreateThis(); method.Signature.Params = ParseParams(); if (method.CallType == CiCallType.Abstract) Expect(CiToken.Semicolon); else method.Body = ParseBlock(); CloseScope(); this.CurrentMethod = null; }
void Write(CiMethod method) { if (method.Visibility == CiVisibility.Dead || method.CallType == CiCallType.Abstract) return; WriteLine(); this.CurrentMethod = method; WriteSignature(method); WriteLine(); OpenBlock(); ICiStatement[] statements = method.Body.Statements; StartBlock(statements); if (method.Throws && method.Signature.ReturnType == CiType.Void && method.Body.CompletesNormally) { if (!TryWriteCallAndReturn(statements, statements.Length - 1, null)) { Write(statements); WriteReturnTrue(); } } else Write(statements); CloseBlock(); this.CurrentMethod = null; }
CiClass ParseClass() { CiClass klass = new CiClass(); klass.SourceFilename = this.Filename; if (Eat(CiToken.Abstract)) klass.IsAbstract = true; Expect(CiToken.Class); klass.Name = ParseId(); if (Eat(CiToken.Colon)) klass.BaseClass = new CiUnknownClass { Name = ParseId() }; Expect(CiToken.LeftBrace); OpenScope(); this.CurrentClass = klass; klass.Members = this.Symbols; while (!Eat(CiToken.RightBrace)) { CiCodeDoc doc = ParseDoc(); CiVisibility visibility = CiVisibility.Private; if (Eat(CiToken.Public)) visibility = CiVisibility.Public; else if (Eat(CiToken.Internal)) visibility = CiVisibility.Internal; CiSymbol symbol; if (See(CiToken.Const)) { symbol = ParseConst(); ((CiConst) symbol).Class = klass; } else if (Eat(CiToken.Macro)) { if (visibility != CiVisibility.Private) throw new ParseException("Macros must be private"); symbol = ParseMacro(); } else { CiCallType callType; if (Eat(CiToken.Static)) callType = CiCallType.Static; else if (Eat(CiToken.Abstract)) { if (!klass.IsAbstract) throw new ParseException("Abstract methods only allowed in abstract classes"); callType = CiCallType.Abstract; if (visibility == CiVisibility.Private) visibility = CiVisibility.Internal; } else if (Eat(CiToken.Virtual)) { callType = CiCallType.Virtual; if (visibility == CiVisibility.Private) visibility = CiVisibility.Internal; } else if (Eat(CiToken.Override)) { callType = CiCallType.Override; if (visibility == CiVisibility.Private) visibility = CiVisibility.Internal; } else callType = CiCallType.Normal; CiType type = ParseReturnType(); if (type is CiClassStorageType && See(CiToken.LeftBrace)) { if (type.Name != klass.Name) throw new ParseException("{0}() looks like a constructor, but it is in a different class {1}", type.Name, klass.Name); if (callType != CiCallType.Normal) throw new ParseException("Constructor cannot be static, abstract, virtual or override"); if (klass.Constructor != null) throw new ParseException("Duplicate constructor"); klass.Constructor = ParseConstructor(); continue; } string name = ParseId(); if (See(CiToken.LeftParenthesis)) { CiMethod method = new CiMethod(type, name) { Class = klass, CallType = callType }; ParseMethod(method); symbol = method; } else { if (visibility != CiVisibility.Private) throw new ParseException("Fields must be private"); if (callType != CiCallType.Normal) throw new ParseException("Fields cannot be static, abstract, virtual or override"); if (type == CiType.Void) throw new ParseException("Field is void"); Expect(CiToken.Semicolon); symbol = new CiField { Class = klass, Type = type, Name = name }; } } symbol.Documentation = doc; symbol.Visibility = visibility; klass.Members.Add(symbol); } this.CurrentClass = null; CloseScope(); klass.ConstArrays = this.ConstArrays.ToArray(); this.ConstArrays.Clear(); return klass; }
protected override void WriteName(CiMethod method) { WriteCamelCase(method.Name); }
void Write(CiClass klass, CiMethod method) { WriteDoc(method); Write(method.Visibility); switch (method.CallType) { case CiCallType.Static: Write("static "); break; case CiCallType.Virtual: break; case CiCallType.Abstract: Write("abstract "); break; case CiCallType.Override: break; case CiCallType.Normal: // no final methods in TS break; case CiCallType.Sealed: // no final methods in TS break; default: throw new NotImplementedException(method.CallType.ToString()); } WriteName(method); Write('('); int i = 0; foreach (CiVar param in method.Parameters) { if (i > 0) { Write(", "); } WriteName(param); if (param.Value != null && !this.GenFullCode) { Write('?'); } Write(": "); Write(param.Type); if (param.Value != null && this.GenFullCode) { WriteVarInit(param); } i++; } Write("): "); Write(method.Type); if (this.GenFullCode) { WriteBody(method); } else { WriteLine(';'); } }
void Write(CiMethod method) { if (method.Visibility == CiVisibility.Public) { Write("=head2 C<"); if (method.CallType == CiCallType.Static) { Write(this.Package); Write(method.Class.Name); Write("::"); } else { Write('$'); WriteLowercase(method.Class.Name); Write("-E<gt>"); } WriteLowercaseWithUnderscores(method.Name); Write('('); bool first = true; foreach (CiParam param in method.Signature.Params) { if (first) first = false; else Write(", "); WriteDocName(param); } WriteLine(")>"); WriteLine(); Write(method.Documentation); if (method.Signature.Params.Any(param => param.Documentation != null)) { WriteLine("Parameters:"); WriteLine(); WriteLine("=over"); WriteLine(); foreach (CiParam param in method.Signature.Params) { Write("=item "); WriteDocName(param); WriteLine(); WriteLine(); Write(param.Documentation); } WriteLine("=back"); WriteLine(); } WriteLine("=cut"); WriteLine(); } if (method.CallType == CiCallType.Abstract) return; this.CurrentMethod = method; Write("sub "); WriteLowercaseWithUnderscores(method.Name); Write('('); if (method.CallType != CiCallType.Static) Write('$'); foreach (CiParam param in method.Signature.Params) Write('$'); Write(") "); OpenBlock(); if (method.CallType != CiCallType.Static || method.Signature.Params.Length > 0) { Write("my ("); bool first = true; if (method.CallType != CiCallType.Static) { Write("$self"); first = false; } foreach (CiParam param in method.Signature.Params) { if (first) first = false; else Write(", "); Write('$'); Write(param.Name); } WriteLine(") = @_;"); } Write(method.Body.Statements); CloseBlock(); WriteLine(); this.CurrentMethod = null; }
void ICiSymbolVisitor.Visit(CiMethod method) { this.CurrentMethod = method; Resolve(method.Signature); if (method.CallType != CiCallType.Abstract) { Resolve(method.Body); if (method.Signature.ReturnType != CiType.Void && method.Body.CompletesNormally) throw new ResolveException("Method can complete without a return value"); } this.CurrentMethod = null; }
CiType LookupType(string name) { CiSymbol symbol = this.Symbols.TryLookup(name); if (symbol is CiType) { return((CiType)symbol); } if (symbol is CiClass) { return new CiClassPtrType { Name = name, Class = (CiClass)symbol } } ; if (symbol == null) { CiType unknown = new CiUnknownType(); unknown.Name = name; return(unknown); } throw new ParseException("{0} is not a type", name); } CiType ParseArrayType(CiType baseType) { if (Eat(CiToken.LeftBracket)) { if (Eat(CiToken.RightBracket)) { return new CiArrayPtrType { ElementType = ParseArrayType(baseType) } } ; CiExpr len = ParseExpr(); Expect(CiToken.RightBracket); return(new CiArrayStorageType { LengthExpr = len, ElementType = ParseArrayType(baseType) }); } return(baseType); } CiType ParseType() { string baseName = ParseId(); CiType baseType; if (Eat(CiToken.LeftParenthesis)) { if (baseName == "string") { baseType = new CiStringStorageType { LengthExpr = ParseExpr() }; Expect(CiToken.RightParenthesis); } else { Expect(CiToken.RightParenthesis); baseType = new CiClassStorageType { Name = baseName, Class = new CiUnknownClass { Name = baseName } }; } } else { baseType = LookupType(baseName); } return(ParseArrayType(baseType)); } object ParseConstInitializer(CiType type) { if (type is CiArrayType) { Expect(CiToken.LeftBrace); CiType elementType = ((CiArrayType)type).ElementType; List <object> list = new List <object>(); if (!See(CiToken.RightBrace)) { do { list.Add(ParseConstInitializer(elementType)); }while (Eat(CiToken.Comma)); } Expect(CiToken.RightBrace); return(list.ToArray()); } return(ParseExpr()); } CiConst ParseConst() { Expect(CiToken.Const); CiConst konst = new CiConst(); konst.Type = ParseType(); konst.Name = ParseId(); Expect(CiToken.Assign); konst.Value = ParseConstInitializer(konst.Type); Expect(CiToken.Semicolon); if (this.Symbols.Parent != null && konst.Type is CiArrayType) { this.ConstArrays.Add(konst); konst.GlobalName = "CiConstArray_" + this.ConstArrays.Count; } return(konst); } CiBinaryResourceExpr ParseBinaryResource() { Expect(CiToken.LeftParenthesis); CiExpr nameExpr = ParseExpr(); Expect(CiToken.RightParenthesis); return(new CiBinaryResourceExpr { NameExpr = nameExpr }); } CiExpr ParsePrimaryExpr() { if (See(CiToken.Increment) || See(CiToken.Decrement) || See(CiToken.Minus) || See(CiToken.Not)) { CiToken op = this.CurrentToken; NextToken(); CiExpr inner = ParsePrimaryExpr(); return(new CiUnaryExpr { Op = op, Inner = inner }); } if (Eat(CiToken.CondNot)) { CiExpr inner = ParsePrimaryExpr(); return(new CiCondNotExpr { Inner = inner }); } CiExpr result; if (See(CiToken.IntConstant)) { result = new CiConstExpr(this.CurrentInt); NextToken(); } else if (See(CiToken.StringConstant)) { result = new CiConstExpr(this.CurrentString); NextToken(); } else if (Eat(CiToken.LeftParenthesis)) { result = ParseExpr(); Expect(CiToken.RightParenthesis); } else if (See(CiToken.Id)) { string name = ParseId(); if (name == "BinaryResource") { result = ParseBinaryResource(); } else { CiSymbol symbol = this.Symbols.TryLookup(name); if (symbol is CiMacro) { Expand((CiMacro)symbol); Expect(CiToken.LeftParenthesis); result = ParseExpr(); Expect(CiToken.RightParenthesis); } else { if (symbol == null) { symbol = new CiUnknownSymbol { Name = name } } ; result = new CiSymbolAccess { Symbol = symbol }; } } } else if (Eat(CiToken.New)) { CiType newType = ParseType(); if (!(newType is CiClassStorageType || newType is CiArrayStorageType)) { throw new ParseException("'new' syntax error"); } result = new CiNewExpr { NewType = newType }; } else { throw new ParseException("Invalid expression"); } for (;;) { if (Eat(CiToken.Dot)) { result = new CiUnknownMemberAccess { Parent = result, Name = ParseId() } } ; else if (Eat(CiToken.LeftParenthesis)) { CiMethodCall call = new CiMethodCall(); call.Obj = result; List <CiExpr> args = new List <CiExpr>(); if (!See(CiToken.RightParenthesis)) { do { args.Add(ParseExpr()); }while (Eat(CiToken.Comma)); } Expect(CiToken.RightParenthesis); call.Arguments = args.ToArray(); result = call; } else if (Eat(CiToken.LeftBracket)) { CiExpr index = ParseExpr(); Expect(CiToken.RightBracket); result = new CiIndexAccess { Parent = result, Index = index }; } else if (See(CiToken.Increment) || See(CiToken.Decrement)) { CiToken op = this.CurrentToken; NextToken(); return(new CiPostfixExpr { Inner = result, Op = op }); } else { return(result); } } } CiExpr ParseMulExpr() { CiExpr left = ParsePrimaryExpr(); while (See(CiToken.Asterisk) || See(CiToken.Slash) || See(CiToken.Mod)) { CiToken op = this.CurrentToken; NextToken(); left = new CiBinaryExpr { Left = left, Op = op, Right = ParsePrimaryExpr() }; } return(left); } CiExpr ParseAddExpr() { CiExpr left = ParseMulExpr(); while (See(CiToken.Plus) || See(CiToken.Minus)) { CiToken op = this.CurrentToken; NextToken(); left = new CiBinaryExpr { Left = left, Op = op, Right = ParseMulExpr() }; } return(left); } CiExpr ParseShiftExpr() { CiExpr left = ParseAddExpr(); while (See(CiToken.ShiftLeft) || See(CiToken.ShiftRight)) { CiToken op = this.CurrentToken; NextToken(); left = new CiBinaryExpr { Left = left, Op = op, Right = ParseAddExpr() }; } return(left); } CiExpr ParseRelExpr() { CiExpr left = ParseShiftExpr(); while (See(CiToken.Less) || See(CiToken.LessOrEqual) || See(CiToken.Greater) || See(CiToken.GreaterOrEqual)) { CiToken op = this.CurrentToken; NextToken(); left = new CiBoolBinaryExpr { Left = left, Op = op, Right = ParseShiftExpr() }; } return(left); } CiExpr ParseEqualityExpr() { CiExpr left = ParseRelExpr(); while (See(CiToken.Equal) || See(CiToken.NotEqual)) { CiToken op = this.CurrentToken; NextToken(); left = new CiBoolBinaryExpr { Left = left, Op = op, Right = ParseRelExpr() }; } return(left); } CiExpr ParseAndExpr() { CiExpr left = ParseEqualityExpr(); while (Eat(CiToken.And)) { left = new CiBinaryExpr { Left = left, Op = CiToken.And, Right = ParseEqualityExpr() } } ; return(left); } CiExpr ParseXorExpr() { CiExpr left = ParseAndExpr(); while (Eat(CiToken.Xor)) { left = new CiBinaryExpr { Left = left, Op = CiToken.Xor, Right = ParseAndExpr() } } ; return(left); } CiExpr ParseOrExpr() { CiExpr left = ParseXorExpr(); while (Eat(CiToken.Or)) { left = new CiBinaryExpr { Left = left, Op = CiToken.Or, Right = ParseXorExpr() } } ; return(left); } CiExpr ParseCondAndExpr() { CiExpr left = ParseOrExpr(); while (Eat(CiToken.CondAnd)) { left = new CiBoolBinaryExpr { Left = left, Op = CiToken.CondAnd, Right = ParseOrExpr() } } ; return(left); } CiExpr ParseCondOrExpr() { CiExpr left = ParseCondAndExpr(); while (Eat(CiToken.CondOr)) { left = new CiBoolBinaryExpr { Left = left, Op = CiToken.CondOr, Right = ParseCondAndExpr() } } ; return(left); } CiExpr ParseExpr() { CiExpr left = ParseCondOrExpr(); if (Eat(CiToken.QuestionMark)) { CiCondExpr result = new CiCondExpr(); result.Cond = left; result.OnTrue = ParseExpr(); Expect(CiToken.Colon); result.OnFalse = ParseExpr(); return(result); } return(left); } CiMaybeAssign ParseMaybeAssign() { CiExpr left = ParseExpr(); CiToken op = this.CurrentToken; if (op == CiToken.Assign || op == CiToken.AddAssign || op == CiToken.SubAssign || op == CiToken.MulAssign || op == CiToken.DivAssign || op == CiToken.ModAssign || op == CiToken.AndAssign || op == CiToken.OrAssign || op == CiToken.XorAssign || op == CiToken.ShiftLeftAssign || op == CiToken.ShiftRightAssign) { NextToken(); CiAssign result = new CiAssign(); result.Target = left; result.Op = op; result.Source = ParseMaybeAssign(); return(result); } return(left); } ICiStatement ParseExprWithSideEffect() { ICiStatement result = ParseMaybeAssign() as ICiStatement; if (result == null) { throw new ParseException("Useless expression"); } return(result); } CiExpr ParseCond() { Expect(CiToken.LeftParenthesis); CiExpr cond = ParseExpr(); Expect(CiToken.RightParenthesis); return(cond); } void OpenScope() { this.Symbols = new SymbolTable { Parent = this.Symbols }; } void CloseScope() { this.Symbols = this.Symbols.Parent; } CiVar ParseVar() { CiVar def = new CiVar(); def.Type = ParseType(); def.Name = ParseId(); if (Eat(CiToken.Assign)) { def.InitialValue = ParseExpr(); } Expect(CiToken.Semicolon); this.Symbols.Add(def); return(def); } ICiStatement ParseVarOrExpr() { string name = this.CurrentString; CiSymbol symbol = this.Symbols.TryLookup(name); if (symbol is CiMacro) { NextToken(); Expand((CiMacro)symbol); return(ParseStatement()); } // try var StringBuilder sb = new StringBuilder(); this.CopyTo = sb; try { return(ParseVar()); } catch (ParseException) { } finally { this.CopyTo = null; } // try expr this.CurrentString = name; this.CurrentToken = CiToken.Id; BeginExpand("ambigous code", sb.ToString(), null); SetReader(new StringReader(sb.ToString())); ICiStatement result = ParseExprWithSideEffect(); Expect(CiToken.Semicolon); return(result); } CiNativeBlock ParseNativeBlock() { StringBuilder sb = new StringBuilder(); this.CopyTo = sb; NextToken(); bool oneLine = true; try { if (See(CiToken.LeftBrace)) { oneLine = false; sb = new StringBuilder(); this.CopyTo = sb; Expect(CiToken.LeftBrace); } int level = 1; for (;;) { if (oneLine && See(CiToken.Semicolon) && level == 1) { break; } if (See(CiToken.EndOfFile)) { throw new ParseException("Native block not terminated"); } if (See(CiToken.LeftBrace)) { level++; } else if (See(CiToken.RightBrace)) { if (--level == 0) { break; } } NextToken(); } } finally { this.CopyTo = null; } NextToken(); Trace.Assert(sb[sb.Length - 1] == '}'); if (!oneLine) { sb.Length--; } else { sb.Append("\n\t"); } return(new CiNativeBlock { Content = sb.ToString() }); } CiSwitch ParseSwitch() { Expect(CiToken.LeftParenthesis); CiSwitch result = new CiSwitch(); result.Value = ParseExpr(); Expect(CiToken.RightParenthesis); Expect(CiToken.LeftBrace); List <CiCase> cases = new List <CiCase>(); while (Eat(CiToken.Case)) { List <object> values = new List <object>(); do { values.Add(ParseExpr()); Expect(CiToken.Colon); } while (Eat(CiToken.Case)); if (See(CiToken.Default)) { throw new ParseException("Please remove case before default"); } CiCase kase = new CiCase { Values = values.ToArray() }; List <ICiStatement> statements = new List <ICiStatement>(); do { statements.Add(ParseStatement()); }while (!See(CiToken.Case) && !See(CiToken.Default) && !See(CiToken.Goto) && !See(CiToken.RightBrace)); kase.Body = statements.ToArray(); if (Eat(CiToken.Goto)) { if (Eat(CiToken.Case)) { kase.FallthroughTo = ParseExpr(); } else if (Eat(CiToken.Default)) { kase.FallthroughTo = null; } else { throw new ParseException("Expected goto case or goto default"); } Expect(CiToken.Semicolon); kase.Fallthrough = true; } cases.Add(kase); } if (cases.Count == 0) { throw new ParseException("Switch with no cases"); } result.Cases = cases.ToArray(); if (Eat(CiToken.Default)) { Expect(CiToken.Colon); List <ICiStatement> statements = new List <ICiStatement>(); do { statements.Add(ParseStatement()); }while (!See(CiToken.RightBrace)); result.DefaultBody = statements.ToArray(); } Expect(CiToken.RightBrace); return(result); } ICiStatement ParseStatement() { while (Eat(CiToken.Macro)) { this.Symbols.Add(ParseMacro()); } if (See(CiToken.Id)) { return(ParseVarOrExpr()); } if (See(CiToken.LeftBrace)) { OpenScope(); CiBlock result = ParseBlock(); CloseScope(); return(result); } if (Eat(CiToken.Break)) { Expect(CiToken.Semicolon); return(new CiBreak()); } if (See(CiToken.Const)) { CiConst konst = ParseConst(); this.Symbols.Add(konst); return(konst); } if (Eat(CiToken.Continue)) { Expect(CiToken.Semicolon); return(new CiContinue()); } if (Eat(CiToken.Delete)) { CiExpr expr = ParseExpr(); Expect(CiToken.Semicolon); return(new CiDelete { Expr = expr }); } if (Eat(CiToken.Do)) { CiDoWhile result = new CiDoWhile(); result.Body = ParseStatement(); Expect(CiToken.While); result.Cond = ParseCond(); Expect(CiToken.Semicolon); return(result); } if (Eat(CiToken.For)) { Expect(CiToken.LeftParenthesis); OpenScope(); CiFor result = new CiFor(); if (See(CiToken.Id)) { result.Init = ParseVarOrExpr(); } else { Expect(CiToken.Semicolon); } if (!See(CiToken.Semicolon)) { result.Cond = ParseExpr(); } Expect(CiToken.Semicolon); if (!See(CiToken.RightParenthesis)) { result.Advance = ParseExprWithSideEffect(); } Expect(CiToken.RightParenthesis); result.Body = ParseStatement(); CloseScope(); return(result); } if (Eat(CiToken.If)) { CiIf result = new CiIf(); result.Cond = ParseCond(); result.OnTrue = ParseStatement(); if (Eat(CiToken.Else)) { result.OnFalse = ParseStatement(); } return(result); } if (See(CiToken.Native)) { return(ParseNativeBlock()); } if (Eat(CiToken.Return)) { CiReturn result = new CiReturn(); if (this.CurrentMethod.Signature.ReturnType != CiType.Void) { result.Value = ParseExpr(); } Expect(CiToken.Semicolon); return(result); } if (Eat(CiToken.Switch)) { return(ParseSwitch()); } if (Eat(CiToken.Throw)) { CiThrow result = new CiThrow(); result.Message = ParseExpr(); Expect(CiToken.Semicolon); return(result); } if (Eat(CiToken.While)) { CiWhile result = new CiWhile(); result.Cond = ParseCond(); result.Body = ParseStatement(); return(result); } throw new ParseException("Invalid statement"); } CiBlock ParseBlock() { Expect(CiToken.LeftBrace); List <ICiStatement> statements = new List <ICiStatement>(); while (!Eat(CiToken.RightBrace)) { statements.Add(ParseStatement()); } return(new CiBlock { Statements = statements.ToArray() }); } CiParam CreateThis() { CiParam thiz = new CiParam(); thiz.Type = new CiClassPtrType { Name = this.CurrentClass.Name, Class = this.CurrentClass }; thiz.Name = "this"; this.Symbols.Add(thiz); return(thiz); } CiType ParseReturnType() { if (Eat(CiToken.Void)) { return(CiType.Void); } return(ParseType()); } CiParam[] ParseParams() { Expect(CiToken.LeftParenthesis); List <CiParam> paramz = new List <CiParam>(); if (!See(CiToken.RightParenthesis)) { do { CiParam param = new CiParam(); param.Documentation = ParseDoc(); param.Type = ParseType(); param.Name = ParseId(); this.Symbols.Add(param); paramz.Add(param); } while (Eat(CiToken.Comma)); } Expect(CiToken.RightParenthesis); return(paramz.ToArray()); } void ParseMethod(CiMethod method) { this.CurrentMethod = method; OpenScope(); if (method.CallType != CiCallType.Static) { method.This = CreateThis(); } method.Signature.Params = ParseParams(); if (method.CallType == CiCallType.Abstract) { Expect(CiToken.Semicolon); } else { method.Body = ParseBlock(); } CloseScope(); this.CurrentMethod = null; } CiMethod ParseConstructor() { NextToken(); Expect(CiToken.LeftParenthesis); Expect(CiToken.RightParenthesis); OpenScope(); CiMethod method = new CiMethod( CiType.Void, "<constructor>") { Class = this.CurrentClass, CallType = CiCallType.Normal, This = CreateThis() }; this.CurrentMethod = method; method.Body = ParseBlock(); CloseScope(); this.CurrentMethod = null; return(method); } CiClass ParseClass() { CiClass klass = new CiClass(); klass.SourceFilename = this.Filename; if (Eat(CiToken.Abstract)) { klass.IsAbstract = true; } Expect(CiToken.Class); klass.Name = ParseId(); if (Eat(CiToken.Colon)) { klass.BaseClass = new CiUnknownClass { Name = ParseId() } } ; Expect(CiToken.LeftBrace); OpenScope(); this.CurrentClass = klass; klass.Members = this.Symbols; while (!Eat(CiToken.RightBrace)) { CiCodeDoc doc = ParseDoc(); CiVisibility visibility = CiVisibility.Private; if (Eat(CiToken.Public)) { visibility = CiVisibility.Public; } else if (Eat(CiToken.Internal)) { visibility = CiVisibility.Internal; } CiSymbol symbol; if (See(CiToken.Const)) { symbol = ParseConst(); ((CiConst)symbol).Class = klass; } else if (Eat(CiToken.Macro)) { if (visibility != CiVisibility.Private) { throw new ParseException("Macros must be private"); } symbol = ParseMacro(); } else { if (See(CiToken.Id) && this.CurrentString == klass.Name) { if (klass.Constructor != null) { throw new ParseException("Duplicate constructor"); } klass.Constructor = ParseConstructor(); continue; } CiCallType callType; if (Eat(CiToken.Static)) { callType = CiCallType.Static; } else if (Eat(CiToken.Abstract)) { if (!klass.IsAbstract) { throw new ParseException("Abstract methods only allowed in abstract classes"); } callType = CiCallType.Abstract; if (visibility == CiVisibility.Private) { visibility = CiVisibility.Internal; } } else if (Eat(CiToken.Virtual)) { callType = CiCallType.Virtual; if (visibility == CiVisibility.Private) { visibility = CiVisibility.Internal; } } else if (Eat(CiToken.Override)) { callType = CiCallType.Override; if (visibility == CiVisibility.Private) { visibility = CiVisibility.Internal; } } else { callType = CiCallType.Normal; } CiType type = ParseReturnType(); string name = ParseId(); if (See(CiToken.LeftParenthesis)) { CiMethod method = new CiMethod(type, name) { Class = klass, CallType = callType }; ParseMethod(method); symbol = method; } else { if (visibility != CiVisibility.Private) { throw new ParseException("Fields must be private"); } if (callType != CiCallType.Normal) { throw new ParseException("Fields cannot be static, abstract, virtual or override"); } if (type == CiType.Void) { throw new ParseException("Field is void"); } Expect(CiToken.Semicolon); symbol = new CiField { Class = klass, Type = type, Name = name }; } } symbol.Documentation = doc; symbol.Visibility = visibility; klass.Members.Add(symbol); } this.CurrentClass = null; CloseScope(); klass.ConstArrays = this.ConstArrays.ToArray(); this.ConstArrays.Clear(); return(klass); } CiDelegate ParseDelegate() { CiDelegate del = new CiDelegate(); Expect(CiToken.Delegate); del.ReturnType = ParseReturnType(); del.Name = ParseId(); OpenScope(); del.Params = ParseParams(); CloseScope(); Expect(CiToken.Semicolon); return(del); } public void Parse(string filename, TextReader reader) { Open(filename, reader); while (!See(CiToken.EndOfFile)) { CiCodeDoc doc = ParseDoc(); bool pub = Eat(CiToken.Public); CiSymbol symbol; if (See(CiToken.Enum)) { symbol = ParseEnum(); } else if (See(CiToken.Class) || See(CiToken.Abstract)) { symbol = ParseClass(); } else if (See(CiToken.Delegate)) { symbol = ParseDelegate(); } else { throw new ParseException("Expected class, enum or delegate"); } symbol.Documentation = doc; symbol.Visibility = pub ? CiVisibility.Public : CiVisibility.Internal; this.Symbols.Add(symbol); } } public CiProgram Program { get { return(new CiProgram { Globals = this.Symbols }); } } } }
protected override void WriteCall(CiExpr obj, CiMethod method, CiExpr[] args, CiPriority parent) { if (obj == null) { WriteLocalName(method, CiPriority.Primary); WriteArgsInParentheses(method, args); } else if (method == CiSystem.StringSubstring) { obj.Accept(this, CiPriority.Primary); Write(".substring("); args[0].Accept(this, CiPriority.Statement); if (args.Length == 2) { Write(", "); WriteAdd(args[0], args[1]); // TODO: side effect } Write(')'); } else if (obj.Type is CiArrayType && method.Name == "CopyTo") { AddLibrary(GenJsMethod.CopyArray, "copyArray : function(sa, soffset, da, doffset, length)", "if (typeof(sa.subarray) == \"function\" && typeof(da.set) == \"function\")", "\tda.set(sa.subarray(soffset, soffset + length), doffset);", "else", "\tfor (let i = 0; i < length; i++)", "\t\tda[doffset + i] = sa[soffset + i];"); Write("Ci.copyArray("); obj.Accept(this, CiPriority.Statement); Write(", "); WriteArgs(method, args); Write(')'); } else if (method == CiSystem.CollectionClear) { if (obj.Type is CiDictionaryType) { Write("for (const key in "); obj.Accept(this, CiPriority.Statement); WriteLine(')'); Write("\tdelete "); obj.Accept(this, CiPriority.Primary); // FIXME: side effect Write("[key];"); } else { obj.Accept(this, CiPriority.Primary); Write(".length = 0"); } } else if (WriteListAddInsert(obj, method, args, "push", "splice", ", 0, ")) { // done } else if (method == CiSystem.ListRemoveAt) { obj.Accept(this, CiPriority.Primary); Write(".splice("); args[0].Accept(this, CiPriority.Statement); Write(", 1)"); } else if (method == CiSystem.ListRemoveRange) { obj.Accept(this, CiPriority.Primary); Write(".splice("); args[0].Accept(this, CiPriority.Statement); Write(", "); args[1].Accept(this, CiPriority.Statement); Write(')'); } else if (obj.Type is CiDictionaryType dict && method.Name == "Add") { if (parent > CiPriority.Assign) { Write('('); } obj.Accept(this, CiPriority.Primary); Write('['); args[0].Accept(this, CiPriority.Statement); Write("] = "); WriteNewStorage(dict.ValueType); if (parent > CiPriority.Assign) { Write(')'); } }
void WriteSignature(CiMethod method) { if (method.Visibility != CiVisibility.Public) Write("static "); var paramz = method.Signature.Params.Select(param => ToString(param.Type, param.Name)); if (method.CallType != CiCallType.Static) paramz = new string[1] { ToString(method.This.Type, "self") }.Concat(paramz); string s = paramz.Any() ? string.Join(", ", paramz.ToArray()) : "void"; s = method.Class.Name + "_" + method.Name + "(" + s + ")"; CiType type = method.Signature.ReturnType; if (method.Throws && type == CiType.Void) type = CiBoolType.Value; Write(type, s); }
protected override void WriteCall(CiExpr obj, CiMethod method, CiExpr[] args, CiPriority parent) { if (obj == null) { WriteName(method); WriteArgsInParentheses(method, args); } else if ((method == CiSystem.StringIndexOf || method == CiSystem.StringLastIndexOf) && IsOneAsciiString(args[0], out char c)) { obj.Accept(this, CiPriority.Primary); Write('.'); Write(method.Name); Write('('); WriteCharLiteral(c); Write(')'); } else if (method == CiSystem.UTF8GetString) { Include("System.Text"); Write("Encoding.UTF8.GetString"); WriteArgsInParentheses(method, args); } else if (method == CiSystem.RegexCompile) { Include("System.Text.RegularExpressions"); Write("new Regex"); WriteArgsInParentheses(method, args); } else if (method == CiSystem.MatchFindStr) { Include("System.Text.RegularExpressions"); Write('('); obj.Accept(this, CiPriority.Assign); Write(" = Regex.Match"); WriteArgsInParentheses(method, args); Write(").Success"); } else if (method == CiSystem.MatchFindRegex) { Include("System.Text.RegularExpressions"); Write('('); obj.Accept(this, CiPriority.Assign); Write(" = "); args[1].Accept(this, CiPriority.Primary); Write(".Match("); args[0].Accept(this, CiPriority.Statement); Write(")).Success"); } else if (method == CiSystem.MatchGetCapture) { obj.Accept(this, CiPriority.Primary); Write(".Groups["); args[0].Accept(this, CiPriority.Statement); Write("].Value"); } else if (obj.Type is CiArrayType && !(obj.Type is CiListType) && method.Name == "CopyTo") { Include("System"); Write("Array.Copy("); obj.Accept(this, CiPriority.Statement); Write(", "); WriteArgs(method, args); Write(')'); } else if (obj.Type is CiArrayStorageType && method.Name == "Fill") { if (!(args[0] is CiLiteral literal) || !literal.IsDefaultValue) { throw new NotImplementedException("Only null, zero and false supported"); } Include("System"); Write("Array.Clear("); obj.Accept(this, CiPriority.Statement); Write(", 0, "); Write(((CiArrayStorageType)obj.Type).Length); Write(')'); } else if (WriteListAddInsert(obj, method, args, "Add", "Insert", ", ")) { // done } else if (obj.Type is CiDictionaryType dict && method.Name == "Add") { obj.Accept(this, CiPriority.Primary); Write(".Add("); args[0].Accept(this, CiPriority.Statement); Write(", "); WriteNewStorage(dict.ValueType); Write(')'); }
void WriteConstructor(CiClass klass) { // TODO: skip constructor if static methods only? if (klass.Visibility == CiVisibility.Public) { Write("=head2 C<$"); WriteLowercase(klass.Name); Write(" = "); Write(this.Package); Write(klass.Name); WriteLine("-E<gt>new()>"); WriteLine(); if (klass.Constructor != null) Write(klass.Constructor.Documentation); WriteLine("=cut"); WriteLine(); } IEnumerable<CiField> classStorageFields = klass.Members .OfType<CiField>().Where(field => field.Type is CiClassStorageType); if (klass.Constructor == null && klass.BaseClass != null && !classStorageFields.Any()) { // base constructor does the job return; } Write("sub new($) "); OpenBlock(); if (klass.BaseClass != null) WriteLine("my $self = shift()->SUPER::new();"); else WriteLine("my $self = bless {}, shift;"); foreach (CiField field in classStorageFields) { Write("$self->{"); WriteLowercaseWithUnderscores(field.Name); Write("} = "); WriteNew(field.Type); WriteLine(";"); } if (klass.Constructor != null) { this.CurrentMethod = klass.Constructor; Write(klass.Constructor.Body.Statements); this.CurrentMethod = null; } WriteLine("return $self;"); // TODO: premature returns CloseBlock(); WriteLine(); }
protected virtual void WriteName(CiMethod method) { Write(method.Name); }
void ICiSymbolVisitor.Visit(CiMethod method) { WriteLine(); Write(method.Documentation); foreach (CiParam param in method.Signature.Params) { if (param.Documentation != null) { Write("/// <param name=\""); Write(param.Name); Write("\">"); Write(param.Documentation.Summary); WriteLine("</param>"); } } Write(method.Visibility); switch (method.CallType) { case CiCallType.Static: Write("static "); break; case CiCallType.Normal: break; case CiCallType.Abstract: Write("abstract "); break; case CiCallType.Virtual: Write("virtual "); break; case CiCallType.Override: Write("override "); break; } WriteSignature(method.Signature); if (method.CallType == CiCallType.Abstract) WriteLine(";"); else { WriteLine(); Write(method.Body); } }
static void MarkThrows(CiMethod method) { if (method.Throws) return; method.Throws = true; method.ErrorReturnValue = GetErrorValue(method.Signature.ReturnType); foreach (CiMethod calledBy in method.CalledBy) MarkThrows(calledBy); }
protected override void WriteCall(CiExpr obj, CiMethod method, CiExpr[] args, CiPriority parent) { if (obj == null) { WriteName(method); WriteArgsInParentheses(method, args); } else if (obj.IsReferenceTo(CiSystem.MathClass)) { Include("cmath"); Write("std::"); WriteMathCall(method, args); } else if (method == CiSystem.StringContains) { if (parent > CiPriority.Equality) { Write('('); } WriteStringMethod(obj, "find", method, args); Write(" != std::string::npos"); if (parent > CiPriority.Equality) { Write(')'); } } else if (method == CiSystem.StringIndexOf) { Write("static_cast<int>("); WriteStringMethod(obj, "find", method, args); Write(')'); } else if (method == CiSystem.StringLastIndexOf) { Write("static_cast<int>("); WriteStringMethod(obj, "rfind", method, args); Write(')'); } else if (method == CiSystem.StringStartsWith) { WriteStringMethod(obj, "starts_with", method, args); } else if (method == CiSystem.StringEndsWith) { WriteStringMethod(obj, "ends_with", method, args); } else if (method == CiSystem.StringSubstring) { WriteStringMethod(obj, "substr", method, args); } else if (obj.Type is CiArrayType && method.Name == "CopyTo") { Include("algorithm"); Write("std::copy_n("); WriteArrayPtrAdd(obj, args[0]); Write(", "); args[3].Accept(this, CiPriority.Statement); Write(", "); WriteArrayPtrAdd(args[1], args[2]); Write(')'); } else if (obj.Type is CiListType list && method.Name == "Add") { if (method.Parameters.Count == 0) { string suffix = ".emplace_back()"; if (!this.AtLineStart) { if (list.ElementType is CiArrayStorageType) { suffix = ".emplace_back().data()"; } else { Write('&'); } } obj.Accept(this, CiPriority.Primary); Write(suffix); } else { obj.Accept(this, CiPriority.Primary); Write(".push_back"); WriteArgsInParentheses(method, args); } }
void Write(CiMethod method) { if (method.CallType == CiCallType.Abstract) return; WriteLine(); Write(method.Class.Name); Write('.'); if (method.CallType != CiCallType.Static) Write("prototype."); WriteCamelCase(method.Name); Write(" = function("); bool first = true; foreach (CiParam param in method.Signature.Params) { if (first) first = false; else Write(", "); Write(param.Name); } Write(") "); Write(method.Body); }
void WriteConstructorNewDelete(CiClass klass) { if (klass.Constructs) { WriteLine(); this.CurrentMethod = klass.Constructor; WriteConstructorSignature(klass); WriteLine(); OpenBlock(); if (klass.Constructor != null) StartBlock(klass.Constructor.Body.Statements); CiClass ptrClass = GetVtblPtrClass(klass); if (HasVtblValue(klass)) { WriteLine("if (vtbl == NULL)"); this.Indent++; Write("vtbl = "); CiClass structClass = GetVtblStructClass(klass); if (structClass != ptrClass) { Write("(const "); Write(ptrClass.Name); Write("Vtbl *) "); } Write("&CiVtbl_"); Write(klass.Name); WriteLine(";"); this.Indent--; } if (ptrClass == klass) WriteLine("self->vtbl = vtbl;"); if (klass.BaseClass != null && klass.BaseClass.Constructs) { Write(klass.BaseClass.Name); Write("_Construct(&self->base"); if (HasVirtualMethods(klass.BaseClass)) Write(", vtbl"); WriteLine(");"); } ForEachStorageField(klass, (field, fieldClass) => { if (fieldClass.Constructs) { Write(fieldClass.Name); Write("_Construct(&self->"); WriteCamelCase(field.Name); if (HasVirtualMethods(fieldClass)) Write(", NULL"); WriteLine(");"); } }); if (klass.Constructor != null) Write(klass.Constructor.Body.Statements); CloseBlock(); this.CurrentMethod = null; } if (!klass.IsAbstract && HasCStruct(klass)) { if (klass.Visibility == CiVisibility.Public) { WriteLine(); WriteNew(klass); WriteLine(); WriteDeleteSignature(klass); WriteLine(); OpenBlock(); WriteLine("free(self);"); CloseBlock(); } else if (klass.IsAllocated) { WriteLine(); Write("static "); WriteNew(klass); } } }
void ICiSymbolVisitor.Visit(CiMethod method) { WriteLine(); WriteDoc(method); WriteVisibility(method); switch (method.CallType) { case CiCallType.Static: Write("static "); break; case CiCallType.Normal: if (method.Visibility != CiVisibility.Private) Write("final "); break; case CiCallType.Override: Write("override "); break; default: break; } Write("function "); WriteCamelCase(method.Name); Write('('); bool first = true; foreach (CiParam param in method.Signature.Params) { if (first) first = false; else Write(", "); Write(param.Name); Write(param.Type); } Write(")"); Write(method.Signature.ReturnType); WriteLine(); OpenBlock(); if (method.CallType == CiCallType.Abstract) WriteLine("throw \"Abstract method called\";"); else { ICiStatement[] statements = method.Body.Statements; Write(statements); if (method.Signature.ReturnType != CiType.Void && statements.Length > 0) { CiFor lastLoop = statements[statements.Length - 1] as CiFor; if (lastLoop != null && lastLoop.Cond == null) WriteLine("throw \"Unreachable\";"); } } CloseBlock(); }
protected override void WriteCall(CiExpr obj, CiMethod method, CiExpr[] args, CiPriority parent) { if (obj == null) { WriteName(method); WriteArgsInParentheses(method, args); } else if ((method == CiSystem.StringIndexOf || method == CiSystem.StringLastIndexOf) && IsOneAsciiString(args[0], out char c)) { obj.Accept(this, CiPriority.Primary); Write('.'); Write(method.Name); Write('('); WriteCharLiteral(c); Write(')'); } else if (method == CiSystem.UTF8GetString) { Include("System.Text"); Write("Encoding.UTF8.GetString"); WriteArgsInParentheses(method, args); } else if (method == CiSystem.RegexCompile) { Include("System.Text.RegularExpressions"); Write("new Regex"); WriteArgsInParentheses(method, args); } else if (method == CiSystem.MatchFindStr) { Include("System.Text.RegularExpressions"); Write('('); obj.Accept(this, CiPriority.Assign); Write(" = Regex.Match"); WriteArgsInParentheses(method, args); Write(").Success"); } else if (method == CiSystem.MatchFindRegex) { Include("System.Text.RegularExpressions"); Write('('); obj.Accept(this, CiPriority.Assign); Write(" = "); WriteCall(args[1], "Match", args[0]); Write(").Success"); } else if (method == CiSystem.MatchGetCapture) { obj.Accept(this, CiPriority.Primary); Write(".Groups["); args[0].Accept(this, CiPriority.Statement); Write("].Value"); } else if (obj.Type is CiArrayType array && method.Name == "BinarySearch") { Include("System"); Write("Array.BinarySearch("); obj.Accept(this, CiPriority.Statement); Write(", "); if (args.Length == 3) { args[1].Accept(this, CiPriority.Statement); Write(", "); args[2].Accept(this, CiPriority.Statement); Write(", "); } WriteNotPromoted(array.ElementType, args[0]); Write(')'); }
void WritePtr(CiMethod method, string name) { StringBuilder sb = new StringBuilder(); sb.Append("(*"); sb.Append(name); sb.Append(")("); sb.Append(method.Class.Name); sb.Append(" *self"); foreach (CiParam param in method.Signature.Params) { sb.Append(", "); sb.Append(ToString(param.Type, param.Name)); } sb.Append(')'); CiType type = method.Signature.ReturnType; if (method.Throws && type == CiType.Void) // TODO: check subclasses type = CiBoolType.Value; Write(type, sb.ToString()); }
static void MarkInternal(CiMethod method) { if (method.Visibility == CiVisibility.Private && method.CalledBy.Any(caller => caller.Class != method.Class)) method.Visibility = CiVisibility.Internal; }
void ICiSymbolVisitor.Visit(CiMethod method) { WriteLine(); WriteDoc(method); if (method.CallType == CiCallType.Override) WriteLine("@Override"); Write(method.Visibility); switch (method.CallType) { case CiCallType.Static: Write("static "); break; case CiCallType.Normal: if (method.Visibility != CiVisibility.Private) Write("final "); break; case CiCallType.Abstract: Write("abstract "); break; default: break; } WriteSignature(method.Signature, method.Name); if (method.Throws) Write(" throws Exception"); if (method.CallType == CiCallType.Abstract) WriteLine(";"); else { WriteLine(); Write(method.Body); } }
protected void WriteArgsInParentheses(CiMethod method, CiExpr[] args) { Write('('); WriteArgs(method, args); Write(')'); }