void WriteRegex(CiExpr[] args, int argIndex) { CiExpr pattern = args[argIndex]; if (pattern.Type.IsClass(CiSystem.RegexClass)) { pattern.Accept(this, CiPriority.Primary); } else if (pattern is CiLiteralString literal) { Write('/'); foreach (char c in literal.Value) { if (c == '/') { Write('\\'); } WriteEscapedChar(c, false); } Write('/'); WriteRegexOptions(args, "", "", "", "i", "m", "s"); } else { Write("new RegExp("); pattern.Accept(this, CiPriority.Argument); WriteRegexOptions(args, ", \"", "", "\"", "i", "m", "s"); Write(')'); } }
void WriteUnwrappedString(CiExpr expr, CiPriority parent, bool substringOk) { if (!(expr is CiLiteral) && expr.Type == CiSystem.StringPtrType) { expr.Accept(this, CiPriority.Primary); Write('!'); } else if (!substringOk && expr is CiCallExpr call && call.Method.IsReferenceTo(CiSystem.StringSubstring)) { Write("String("); expr.Accept(this, CiPriority.Statement); Write(')'); }
void WriteNewRegExp(CiExpr[] args) { CiExpr pattern = args[1]; if (pattern is CiLiteral literal) { Write('/'); foreach (char c in (string)literal.Value) { if (c == '/') { Write('\\'); } WriteEscapedChar(c, false); } Write('/'); WriteRegexOptions(args, "", "", "", "i", "m", "s"); } else { Write("new RegExp("); pattern.Accept(this, CiPriority.Statement); WriteRegexOptions(args, ", \"", "", "\"", "i", "m", "s"); Write(')'); } }
protected override void WriteStringLength(CiExpr expr) { this.StringLength = true; Write("strlen("); expr.Accept(this, CiPriority.Statement); Write(')'); }
protected void WriteCall(string function, CiExpr arg0) { Write(function); Write('('); arg0.Accept(this, CiPriority.Argument); Write(')'); }
protected override void WriteCoercedLiteral(CiType type, CiExpr literal) { literal.Accept(this, CiPriority.Argument); if (type == CiSystem.FloatType) { Write('f'); } }
protected override void WriteStaticCast(string type, CiExpr expr) { Write("static_cast<"); Write(type); Write(">("); expr.Accept(this, CiPriority.Statement); Write(')'); }
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 WriteCall(string function, CiExpr arg0, CiExpr arg1) { Write(function); Write('('); arg0.Accept(this, CiPriority.Statement); Write(", "); arg1.Accept(this, CiPriority.Statement); Write(')'); }
protected override void WriteNewArray(CiType elementType, CiExpr lengthExpr, CiPriority parent) { Include("memory"); Write("std::make_shared<"); Write(elementType, false); Write("[]>("); lengthExpr.Accept(this, CiPriority.Statement); Write(')'); }
void OpenIndexing(CiExpr array) { array.Accept(this, CiPriority.Primary); if (array.Type is CiArrayPtrType) { Write('!'); } Write('['); }
public override CiExpr Visit(CiInterpolatedString expr, CiPriority parent) { if (expr.Suffix.Length == 0 && expr.Parts.Length == 1 && expr.Parts[0].Prefix.Length == 0 && expr.Parts[0].WidthExpr == null && expr.Parts[0].Format == ' ') { CiExpr arg = expr.Parts[0].Argument; if (arg.Type == CiSystem.LongType) { Write("Long"); } else if (arg.Type == CiSystem.DoubleType || arg.Type == CiSystem.FloatIntType) { Write("Double"); } else if (arg.Type == CiSystem.FloatType) { Write("Float"); } else if (arg.Type is CiStringType) { arg.Accept(this, parent); return(expr); } else { Write("Integer"); } Write(".toString("); arg.Accept(this, CiPriority.Statement); Write(')'); } else { Write("String.format("); WritePrintf(expr, false); } return(expr); }
protected void WriteCall(string function, CiExpr arg0, CiExpr[] args) { Write(function); Write('('); arg0.Accept(this, CiPriority.Argument); foreach (CiExpr arg in args) { Write(", "); arg.Accept(this, CiPriority.Argument); } Write(')'); }
protected override void WriteFallthrough(CiExpr expr) { if (expr is CiGotoDefault) { WriteLine("goto default;"); } else { Write("goto case "); expr.Accept(this, CiPriority.Statement); WriteLine(';'); } }
protected void WriteArrayPtrAdd(CiExpr array, CiExpr index) { if (index.IsLiteralZero) { WriteArrayPtr(array, CiPriority.Argument); } else { WriteArrayPtr(array, CiPriority.Add); Write(" + "); index.Accept(this, CiPriority.Add); } }
protected override void WriteNewArray(CiType elementType, CiExpr lengthExpr, CiPriority parent) { Write("new "); Write(elementType.BaseType, false); Write('['); lengthExpr.Accept(this, CiPriority.Statement); Write(']'); while (elementType is CiArrayType array) { Write("[]"); elementType = array.ElementType; } }
protected void WriteListAppend(CiExpr obj, CiExpr[] args) { obj.Accept(this, CiPriority.Primary); Write(".append("); if (args.Length == 0) { WriteNewStorage(((CiCollectionType)obj.Type).ElementType); } else { args[0].Accept(this, CiPriority.Argument); } Write(')'); }
protected override void WriteNewArray(CiType elementType, CiExpr lengthExpr, CiPriority parent) { Write("new "); Write(elementType.BaseType, false); Write('['); lengthExpr.Accept(this, CiPriority.Argument); Write(']'); while (elementType is CiArrayType array) { Write('['); if (array is CiArrayStorageType arrayStorage) { arrayStorage.LengthExpr.Accept(this, CiPriority.Argument); } Write(']'); elementType = array.ElementType; } }
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); } }
protected override void WriteStringLength(CiExpr expr) { expr.Accept(this, CiPriority.Primary); Write(".length"); }
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(')'); }
protected override void WriteCall(CiExpr obj, CiMethod method, CiExpr[] args, CiPriority parent) { if (obj.Type is CiArrayType && !(obj.Type is CiListType) && method.Name == "CopyTo") { Write("System.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"); } Write("System.Array.Clear("); obj.Accept(this, CiPriority.Statement); Write(", 0, "); Write(((CiArrayStorageType)obj.Type).Length); Write(')'); } else if (method == CiSystem.ArraySort) { if (obj.Type is CiArrayStorageType) { Write("System.Array.Sort("); obj.Accept(this, CiPriority.Statement); Write(')'); } else { obj.Accept(this, CiPriority.Primary); Write(".Sort()"); } } 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) { Write("System.Text.Encoding.UTF8.GetString"); WriteArgsInParentheses(method, args); } else { if (method == CiSystem.ConsoleWrite || method == CiSystem.ConsoleWriteLine || IsMathReference(obj)) { Write("System."); } obj.Accept(this, CiPriority.Primary); Write('.'); Write(method.Name); WriteArgsInParentheses(method, args); } }
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); } }
CiExpr Resolve(CiExpr expr) { return expr.Accept(this); }
protected virtual void WriteCoercedInternal(CiType type, CiExpr expr, CiPriority parent) { expr.Accept(this, parent); }
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(')'); }
protected void WriteCall(CiExpr obj, string method, CiExpr arg0, CiExpr arg1) { obj.Accept(this, CiPriority.Primary); Write('.'); WriteCall(method, arg0, arg1); }
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 array && method.Name == "BinarySearch") { Include("algorithm"); if (parent > CiPriority.Add) { Write('('); } Write("std::lower_bound("); if (args.Length == 1) { obj.Accept(this, CiPriority.Primary); Write(".begin(), "); obj.Accept(this, CiPriority.Primary); // FIXME: side effect Write(".end()"); } else { WriteArrayPtrAdd(obj, args[1]); Write(", "); WriteArrayPtrAdd(obj, args[1]); // FIXME: side effect Write(" + "); args[2].Accept(this, CiPriority.Add); } Write(", "); args[0].Accept(this, CiPriority.Statement); Write(") - "); WriteArrayPtr(obj, CiPriority.Mul); if (parent > CiPriority.Add) { Write(')'); } }
protected override void WriteNewArray(CiType elementType, CiExpr lengthExpr, CiPriority parent) { if (!(elementType is CiNumericType)) { Write("new Array("); lengthExpr.Accept(this, CiPriority.Statement); Write(')'); return; } string name; int shift; if (elementType == CiSystem.IntType) { name = "Int32"; shift = 2; } else if (elementType == CiSystem.DoubleType) { name = "Float64"; shift = 3; } else if (elementType == CiSystem.FloatType) { name = "Float32"; shift = 2; } else if (elementType == CiSystem.LongType) { // TODO: UInt32 if possible? name = "Float64"; // no 64-bit integers in JavaScript shift = 3; } else { CiRangeType range = (CiRangeType)elementType; if (range.Min < 0) { if (range.Min < short.MinValue || range.Max > short.MaxValue) { name = "Int32"; shift = 2; } else if (range.Min < sbyte.MinValue || range.Max > sbyte.MaxValue) { name = "Int16"; shift = 1; } else { name = "Int8"; shift = 0; } } else if (range.Max > ushort.MaxValue) { name = "Int32"; shift = 2; } else if (range.Max > byte.MaxValue) { name = "Uint16"; shift = 1; } else { name = "Uint8"; shift = 0; } } Write("new "); Write(name); Write("Array(new ArrayBuffer("); if (shift == 0) { lengthExpr.Accept(this, CiPriority.Statement); } else if (lengthExpr is CiLiteral literalLength) { Write(((long)literalLength.Value) << shift); } else { lengthExpr.Accept(this, CiPriority.Shift); Write(" << "); Write(shift); } Write("))"); }
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(')'); } }
protected virtual void WriteExpr(CiExpr expr, CiPriority parent) { expr.Accept(this, parent); }