diff options
author | Piotr Fusik <piotr@fusion-lang.org> | 2024-02-19 14:55:51 +0100 |
---|---|---|
committer | Piotr Fusik <piotr@fusion-lang.org> | 2024-02-19 14:55:51 +0100 |
commit | 1e4e00455e3299770049c6a68275974799148dbb (patch) | |
tree | 1d4adfe0e0c22f6dfd248b8d57269e229244236d | |
parent | 6617ede213e784a2b6f13d3915cb040a11ad3abb (diff) |
[json] JavaScript.
#140
-rw-r--r-- | AST.fu | 3 | ||||
-rw-r--r-- | GenJs.fu | 42 | ||||
-rw-r--r-- | GenTs.fu | 5 | ||||
-rw-r--r-- | Sema.fu | 2 | ||||
-rw-r--r-- | libfut.cpp | 50 | ||||
-rw-r--r-- | libfut.cs | 51 | ||||
-rw-r--r-- | libfut.hpp | 1 | ||||
-rw-r--r-- | libfut.js | 51 | ||||
-rw-r--r-- | test/JsonElement.fu | 2 |
9 files changed, 201 insertions, 6 deletions
@@ -1051,7 +1051,7 @@ public abstract class FuNamedValue : FuSymbol { internal FuExpr#? TypeExpr; internal FuExpr#? Value; - public bool IsAssignableStorage() => this.Type is FuStorageType && !(this.Type is FuArrayStorageType) && this.Value is FuLiteralNull; + public bool IsAssignableStorage() => this.Type is FuStorageType storage && !(this.Type is FuArrayStorageType) && (this.Value is FuLiteralNull || storage.Class.Id == FuId.JsonElementClass); } public abstract class FuMember : FuNamedValue @@ -1749,4 +1749,5 @@ public class FuProgram : FuScope internal FuMethod? Main = null; internal SortedDictionary<string(), List<byte>()>() Resources; internal bool RegexOptionsEnum = false; + internal bool JsonValueKindEnum = false; } @@ -406,6 +406,9 @@ public class GenJsNoModule : GenBase case FuId.MatchValue: WritePostfix(expr.Left, "[0]"); break; + case FuId.JsonElementValueKind: + WriteCall("JsonValueKind.get", expr.Left); + break; case FuId.MathNaN: Write("NaN"); break; @@ -847,6 +850,17 @@ public class GenJsNoModule : GenBase case FuId.MatchGetCapture: WriteIndexing(obj, args[0]); break; + case FuId.JsonElementParse: + obj.Accept(this, FuPriority.Assign); + WriteCall(" = JSON.parse", args[0]); + break; + case FuId.JsonElementGetObject: + case FuId.JsonElementGetArray: + case FuId.JsonElementGetString: + case FuId.JsonElementGetDouble: + case FuId.JsonElementGetBoolean: + obj.Accept(this, parent); + break; case FuId.MathAbs: WriteCall(args[0].Type.Id == FuId.LongType ? "(x => x < 0n ? -x : x)" : "Math.abs", args[0]); break; @@ -1318,6 +1332,34 @@ public class GenJsNoModule : GenBase protected void WriteLib!(FuProgram program) { + if (program.JsonValueKindEnum) { + WriteNewLine(); + Write("const JsonValueKind = "); + OpenBlock(); + WriteLine("OBJECT : 1,"); + WriteLine("ARRAY : 2,"); + WriteLine("STRING : 3,"); + WriteLine("NUMBER : 4,"); + WriteLine("TRUE : 5,"); + WriteLine("FALSE : 6,"); + WriteLine("NULL : 7,"); + Write("get : e => "); + OpenBlock(); + Write("switch (typeof(e)) "); + OpenBlock(); + WriteLine("case \"string\":"); + WriteLine("\treturn JsonValueKind.STRING;"); + WriteLine("case \"number\":"); + WriteLine("\treturn JsonValueKind.NUMBER;"); + WriteLine("case \"boolean\":"); + WriteLine("\treturn e ? JsonValueKind.TRUE : JsonValueKind.FALSE;"); + WriteLine("default:"); + WriteLine("\treturn Array.isArray(e) ? JsonValueKind.ARRAY: e === null ? JsonValueKind.NULL : JsonValueKind.OBJECT;"); + CloseBlock(); + CloseBlock(); + WriteNewLine(); + CloseBlock(); + } if (this.StringWriter) { WriteNewLine(); WriteLine("class StringWriter"); @@ -1,7 +1,7 @@ // GenTs.fu - TypeScript code generator // // Copyright (C) 2020-2021 Andy Edwards -// Copyright (C) 2020-2023 Piotr Fusik +// Copyright (C) 2020-2024 Piotr Fusik // // This file is part of Fusion Transpiler, // see https://github.com/fusionlanguage/fut @@ -131,6 +131,9 @@ public class GenTs : GenJs case FuId.MatchClass: Write("RegExpMatchArray"); break; + case FuId.JsonElementClass: + Write("any"); + break; default: Write(klass.Class.Name); break; @@ -234,6 +234,8 @@ public class FuSema } else if (symbol.Symbol.Id == FuId.RegexOptionsEnum) this.Program.RegexOptionsEnum = true; + else if (symbol.Symbol.Id == FuId.JsonValueKindEnum) + this.Program.JsonValueKindEnum = true; } return resolved; } @@ -1961,7 +1961,8 @@ bool FuFloatingType::isAssignableFrom(const FuType * right) const bool FuNamedValue::isAssignableStorage() const { - return dynamic_cast<const FuStorageType *>(this->type.get()) && !dynamic_cast<const FuArrayStorageType *>(this->type.get()) && dynamic_cast<const FuLiteralNull *>(this->value.get()); + const FuStorageType * storage; + return (storage = dynamic_cast<const FuStorageType *>(this->type.get())) && !dynamic_cast<const FuArrayStorageType *>(this->type.get()) && (dynamic_cast<const FuLiteralNull *>(this->value.get()) || storage->class_->id == FuId::jsonElementClass); } FuMember::FuMember() { @@ -4296,6 +4297,8 @@ std::shared_ptr<FuExpr> FuSema::visitSymbolReference(std::shared_ptr<FuSymbolRef } else if (symbol->symbol->id == FuId::regexOptionsEnum) this->program->regexOptionsEnum = true; + else if (symbol->symbol->id == FuId::jsonValueKindEnum) + this->program->jsonValueKindEnum = true; } return resolved; } @@ -18937,6 +18940,9 @@ void GenJsNoModule::visitSymbolReference(const FuSymbolReference * expr, FuPrior case FuId::matchValue: writePostfix(expr->left.get(), "[0]"); break; + case FuId::jsonElementValueKind: + writeCall("JsonValueKind.get", expr->left.get()); + break; case FuId::mathNaN: write("NaN"); break; @@ -19383,6 +19389,17 @@ void GenJsNoModule::writeCallExpr(const FuExpr * obj, const FuMethod * method, c case FuId::matchGetCapture: writeIndexing(obj, (*args)[0].get()); break; + case FuId::jsonElementParse: + obj->accept(this, FuPriority::assign); + writeCall(" = JSON.parse", (*args)[0].get()); + break; + case FuId::jsonElementGetObject: + case FuId::jsonElementGetArray: + case FuId::jsonElementGetString: + case FuId::jsonElementGetDouble: + case FuId::jsonElementGetBoolean: + obj->accept(this, parent); + break; case FuId::mathAbs: writeCall((*args)[0]->type->id == FuId::longType ? "(x => x < 0n ? -x : x)" : "Math.abs", (*args)[0].get()); break; @@ -19840,6 +19857,34 @@ void GenJsNoModule::writeMain(const FuMethod * main) void GenJsNoModule::writeLib(const FuProgram * program) { + if (program->jsonValueKindEnum) { + writeNewLine(); + write("const JsonValueKind = "); + openBlock(); + writeLine("OBJECT : 1,"); + writeLine("ARRAY : 2,"); + writeLine("STRING : 3,"); + writeLine("NUMBER : 4,"); + writeLine("TRUE : 5,"); + writeLine("FALSE : 6,"); + writeLine("NULL : 7,"); + write("get : e => "); + openBlock(); + write("switch (typeof(e)) "); + openBlock(); + writeLine("case \"string\":"); + writeLine("\treturn JsonValueKind.STRING;"); + writeLine("case \"number\":"); + writeLine("\treturn JsonValueKind.NUMBER;"); + writeLine("case \"boolean\":"); + writeLine("\treturn e ? JsonValueKind.TRUE : JsonValueKind.FALSE;"); + writeLine("default:"); + writeLine("\treturn Array.isArray(e) ? JsonValueKind.ARRAY: e === null ? JsonValueKind.NULL : JsonValueKind.OBJECT;"); + closeBlock(); + closeBlock(); + writeNewLine(); + closeBlock(); + } if (this->stringWriter) { writeNewLine(); writeLine("class StringWriter"); @@ -20003,6 +20048,9 @@ void GenTs::writeType(const FuType * type, bool readOnly) case FuId::matchClass: write("RegExpMatchArray"); break; + case FuId::jsonElementClass: + write("any"); + break; default: write(klass->class_->name); break; @@ -2551,7 +2551,7 @@ namespace Fusion internal FuExpr Value; - public bool IsAssignableStorage() => this.Type is FuStorageType && !(this.Type is FuArrayStorageType) && this.Value is FuLiteralNull; + public bool IsAssignableStorage() => this.Type is FuStorageType storage && !(this.Type is FuArrayStorageType) && (this.Value is FuLiteralNull || storage.Class.Id == FuId.JsonElementClass); } public abstract class FuMember : FuNamedValue @@ -3326,6 +3326,8 @@ namespace Fusion internal readonly SortedDictionary<string, List<byte>> Resources = new SortedDictionary<string, List<byte>>(); internal bool RegexOptionsEnum = false; + + internal bool JsonValueKindEnum = false; } public class FuParser : FuLexer @@ -4591,6 +4593,8 @@ namespace Fusion } else if (symbol.Symbol.Id == FuId.RegexOptionsEnum) this.Program.RegexOptionsEnum = true; + else if (symbol.Symbol.Id == FuId.JsonValueKindEnum) + this.Program.JsonValueKindEnum = true; } return resolved; } @@ -19575,6 +19579,9 @@ namespace Fusion case FuId.MatchValue: WritePostfix(expr.Left, "[0]"); break; + case FuId.JsonElementValueKind: + WriteCall("JsonValueKind.get", expr.Left); + break; case FuId.MathNaN: Write("NaN"); break; @@ -20015,6 +20022,17 @@ namespace Fusion case FuId.MatchGetCapture: WriteIndexing(obj, args[0]); break; + case FuId.JsonElementParse: + obj.Accept(this, FuPriority.Assign); + WriteCall(" = JSON.parse", args[0]); + break; + case FuId.JsonElementGetObject: + case FuId.JsonElementGetArray: + case FuId.JsonElementGetString: + case FuId.JsonElementGetDouble: + case FuId.JsonElementGetBoolean: + obj.Accept(this, parent); + break; case FuId.MathAbs: WriteCall(args[0].Type.Id == FuId.LongType ? "(x => x < 0n ? -x : x)" : "Math.abs", args[0]); break; @@ -20482,6 +20500,34 @@ namespace Fusion protected void WriteLib(FuProgram program) { + if (program.JsonValueKindEnum) { + WriteNewLine(); + Write("const JsonValueKind = "); + OpenBlock(); + WriteLine("OBJECT : 1,"); + WriteLine("ARRAY : 2,"); + WriteLine("STRING : 3,"); + WriteLine("NUMBER : 4,"); + WriteLine("TRUE : 5,"); + WriteLine("FALSE : 6,"); + WriteLine("NULL : 7,"); + Write("get : e => "); + OpenBlock(); + Write("switch (typeof(e)) "); + OpenBlock(); + WriteLine("case \"string\":"); + WriteLine("\treturn JsonValueKind.STRING;"); + WriteLine("case \"number\":"); + WriteLine("\treturn JsonValueKind.NUMBER;"); + WriteLine("case \"boolean\":"); + WriteLine("\treturn e ? JsonValueKind.TRUE : JsonValueKind.FALSE;"); + WriteLine("default:"); + WriteLine("\treturn Array.isArray(e) ? JsonValueKind.ARRAY: e === null ? JsonValueKind.NULL : JsonValueKind.OBJECT;"); + CloseBlock(); + CloseBlock(); + WriteNewLine(); + CloseBlock(); + } if (this.StringWriter) { WriteNewLine(); WriteLine("class StringWriter"); @@ -20663,6 +20709,9 @@ namespace Fusion case FuId.MatchClass: Write("RegExpMatchArray"); break; + case FuId.JsonElementClass: + Write("any"); + break; default: Write(klass.Class.Name); break; @@ -1503,6 +1503,7 @@ public: const FuMethod * main = nullptr; std::map<std::string, std::vector<uint8_t>> resources; bool regexOptionsEnum = false; + bool jsonValueKindEnum = false; }; class FuParser : public FuLexer @@ -2593,7 +2593,8 @@ export class FuNamedValue extends FuSymbol isAssignableStorage() { - return this.type instanceof FuStorageType && !(this.type instanceof FuArrayStorageType) && this.value instanceof FuLiteralNull; + let storage; + return (storage = this.type) instanceof FuStorageType && !(this.type instanceof FuArrayStorageType) && (this.value instanceof FuLiteralNull || storage.class.id == FuId.JSON_ELEMENT_CLASS); } } @@ -3467,6 +3468,7 @@ export class FuProgram extends FuScope main = null; resources = {}; regexOptionsEnum = false; + jsonValueKindEnum = false; } export class FuParser extends FuLexer @@ -4742,6 +4744,8 @@ export class FuSema } else if (symbol.symbol.id == FuId.REGEX_OPTIONS_ENUM) this.program.regexOptionsEnum = true; + else if (symbol.symbol.id == FuId.JSON_VALUE_KIND_ENUM) + this.program.jsonValueKindEnum = true; } return resolved; } @@ -20128,6 +20132,9 @@ export class GenJsNoModule extends GenBase case FuId.MATCH_VALUE: this.writePostfix(expr.left, "[0]"); break; + case FuId.JSON_ELEMENT_VALUE_KIND: + this.writeCall("JsonValueKind.get", expr.left); + break; case FuId.MATH_NA_N: this.write("NaN"); break; @@ -20573,6 +20580,17 @@ export class GenJsNoModule extends GenBase case FuId.MATCH_GET_CAPTURE: this.writeIndexing(obj, args[0]); break; + case FuId.JSON_ELEMENT_PARSE: + obj.accept(this, FuPriority.ASSIGN); + this.writeCall(" = JSON.parse", args[0]); + break; + case FuId.JSON_ELEMENT_GET_OBJECT: + case FuId.JSON_ELEMENT_GET_ARRAY: + case FuId.JSON_ELEMENT_GET_STRING: + case FuId.JSON_ELEMENT_GET_DOUBLE: + case FuId.JSON_ELEMENT_GET_BOOLEAN: + obj.accept(this, parent); + break; case FuId.MATH_ABS: this.writeCall(args[0].type.id == FuId.LONG_TYPE ? "(x => x < 0n ? -x : x)" : "Math.abs", args[0]); break; @@ -21033,6 +21051,34 @@ export class GenJsNoModule extends GenBase writeLib(program) { + if (program.jsonValueKindEnum) { + this.writeNewLine(); + this.write("const JsonValueKind = "); + this.openBlock(); + this.writeLine("OBJECT : 1,"); + this.writeLine("ARRAY : 2,"); + this.writeLine("STRING : 3,"); + this.writeLine("NUMBER : 4,"); + this.writeLine("TRUE : 5,"); + this.writeLine("FALSE : 6,"); + this.writeLine("NULL : 7,"); + this.write("get : e => "); + this.openBlock(); + this.write("switch (typeof(e)) "); + this.openBlock(); + this.writeLine("case \"string\":"); + this.writeLine("\treturn JsonValueKind.STRING;"); + this.writeLine("case \"number\":"); + this.writeLine("\treturn JsonValueKind.NUMBER;"); + this.writeLine("case \"boolean\":"); + this.writeLine("\treturn e ? JsonValueKind.TRUE : JsonValueKind.FALSE;"); + this.writeLine("default:"); + this.writeLine("\treturn Array.isArray(e) ? JsonValueKind.ARRAY: e === null ? JsonValueKind.NULL : JsonValueKind.OBJECT;"); + this.closeBlock(); + this.closeBlock(); + this.writeNewLine(); + this.closeBlock(); + } if (this.#stringWriter) { this.writeNewLine(); this.writeLine("class StringWriter"); @@ -21210,6 +21256,9 @@ export class GenTs extends GenJs case FuId.MATCH_CLASS: this.write("RegExpMatchArray"); break; + case FuId.JSON_ELEMENT_CLASS: + this.write("any"); + break; default: this.write(klass.class.name); break; diff --git a/test/JsonElement.fu b/test/JsonElement.fu index f622b9c..d8366dc 100644 --- a/test/JsonElement.fu +++ b/test/JsonElement.fu @@ -2,7 +2,7 @@ public static class Test { public static bool Run() { - JsonElement() json; //FAIL: c cpp d java js py swift ts TODO; cl + JsonElement() json; //FAIL: c cpp d java py swift TODO; cl json.Parse("\"foo\""); if (json.ValueKind != JsonValueKind.String || json.GetString() != "foo") return false; |