Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TLS-14 Sir to JavaScript #2

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1",
"globals": "^15.13.0",
"prettier": "^3.4.1",
"prettier": "^3.4.2",
"tsx": "^4.19.2",
"typescript": "^5.7.2",
"typescript-eslint": "^8.17.0"
},
"type": "module",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"start": "tsx src/cli.ts",
"lint": "eslint src/**/*.ts",
"format": "prettier --write .",
"ts-check": "tsc --noEmit"
Expand Down
67 changes: 0 additions & 67 deletions sample.json

This file was deleted.

54 changes: 43 additions & 11 deletions sample.sia
Original file line number Diff line number Diff line change
@@ -1,18 +1,50 @@
schema Person {
name text
age? int32(min = 0, max = 120)
email? text(encoding = "ascii")
tags text[]
name string8
age? string(min = 0, max = 120)
ageNumber? int32
email? string8(encoding = "ascii")
ageArray? int8[]
ageArray2? int16[]
ageArray3? int32[]
ageArray4? int64[]
footSizeArray? uint8[]
footSizeArray2? uint16[]
footSizeArray3? uint32[]
footSizeArray4? uint64[]
tags8 string8[]
tags16 string16[]
tags32 string32[]
tags64 string64[]
tagsByteArray8 byte8[]
tagsByteArray16 byte16[]
tagsByteArray32 byte32[]
tagsByteArray64 byte64[]
tagsBool bool[]
tagsBigInt bigint[]
tagsArray8 array8[]
tagsArray16 array16[]
tagsArray32 array32[]
tagsArray64 array64[]
address Address
isAdmin bool
billingInfo? BillingInfo
}

schema Address {
street text = "Default Street"
city text
zip int32
street string8 = "Default Street"
city string8
zip string(min = 5, max = 5)
country Country
}

function add returns int64 {
lhs int32
rhs int32
}
schema Country {
name string8
code string(min = 2, max = 2)
codeArray string8[]
flag string8
}

schema BillingInfo {
cardNumber string8
expiryDate string8
}
45 changes: 26 additions & 19 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#!/usr/bin/env node

import { ILexingError, IRecognitionException } from "chevrotain";
import { Command } from "commander";
import { readFileSync, writeFileSync } from "fs";
import { generateSia, getExtension } from "./generator/index.js";
import { compile } from "./index.js";
import { logError } from "./utils/log.js";

import { ILexingError, IRecognitionException } from "chevrotain";

const program = new Command();

program
Expand All @@ -18,30 +18,37 @@ program
.command("compile")
.description("Compile a .sia file")
.argument("<file>", "file to compile")
.option("-s, --string", "display the result as a string")
.option("-o, --output <file>", "output the result to a file")
.option("-s, --generate-sir", "generate the sir file")
.option("-e, --extension <extension>", "extension of the output file")
.action(async (file, options) => {
const extension = getExtension(options.extension);

if (!extension) {
console.error("Invalid extension");
process.exitCode = 1;
return;
}

const src = readFileSync(file, "utf-8");
try {
const result = compile(src);

if (options.string) {
try {
return console.log(JSON.stringify(result, null, 2));
} catch (error) {
console.error(error);
process.exitCode = 1;
return;
}
const sir = compile(src);

if (options.generateSir) {
const outputFile = file.replace(".sia", ".json");
writeFileSync(outputFile, JSON.stringify(sir, null, 2));
console.info(`Sir file written to ${outputFile}`);
}

if (options.output) {
writeFileSync(options.output, JSON.stringify(result, null, 2));
console.log(`Output written to ${options.output}`);
return;
if (options.extension) {
console.info(`Generating ${extension} file`);
} else {
console.info(`Detected extension: ${extension}`);
}

return console.dir(result, { depth: null });
const newFileName = file.replace(".sia", `.${extension}`);
const generatedSia = await generateSia(sir, extension);
writeFileSync(newFileName, generatedSia);
console.info(`Sia file written to ${newFileName}`);
} catch (error) {
logError(src, file, error as ILexingError | IRecognitionException);
process.exitCode = 1;
Expand Down
86 changes: 86 additions & 0 deletions src/generator/common/js/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { FieldDefinition, SchemaDefinition } from "../../../visitor.js";
import { SiaType } from "../types.js";
import { siaTypeSerializerArrayItemMap } from "./maps.js";
import { createAttributeString } from "./strings.js";

export const isAnyString = (type: SiaType) => {
return [
SiaType.String8,
SiaType.String16,
SiaType.String32,
SiaType.String64,
].includes(type);
};

export const getStringTypeFromLength = (max: number = 255) => {
if (max <= 255) return SiaType.String8;
if (max <= 65535) return SiaType.String16;
if (max <= 4294967295) return SiaType.String32;
return SiaType.String64;
};

export const getRequiredSerializers = (schemas: SchemaDefinition[]) => {
return Array.from(
new Set(
schemas
.map((schema) => schema.fields.filter((field) => field.isArray))
.flat()
.filter(Boolean)
.map(
(field) =>
siaTypeSerializerArrayItemMap[
field.type as keyof typeof siaTypeSerializerArrayItemMap
],
),
),
);
};

export const getDefaultValueForType = (
field: SchemaDefinition["fields"][0],
): string => {
if (field.defaultValue) {
return `"${field.defaultValue}"`;
}

if (field.type.startsWith("int") || field.type.startsWith("uint")) {
return "0";
}

if (field.type === "bool") {
return "false";
}

return '""';
};

export const generateAttribute = (
field: FieldDefinition,
schemas: SchemaDefinition[],
): string => {
if (field.isArray) {
return createAttributeString(field.name, "[]");
}

if (!Object.values(SiaType).includes(field.type as SiaType)) {
return generateNestedObjectAttribute(field, schemas);
}

return createAttributeString(field.name, getDefaultValueForType(field));
};

export const generateNestedObjectAttribute = (
field: SchemaDefinition["fields"][0],
schemas: SchemaDefinition[],
): string => {
const referencedSchema = schemas.find((s) => s.name === field.type);
if (!referencedSchema) {
throw new Error(`Referenced schema ${field.type} not found`);
}

const nestedFields = referencedSchema.fields
.map((nestedField) => generateAttribute(nestedField, schemas))
.join("\n");

return createAttributeString(field.name, `{\n${nestedFields}\n}`);
};
53 changes: 53 additions & 0 deletions src/generator/common/js/maps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { SiaType } from "../types.js";

export const siaTypeFunctionMap: Record<SiaType, string> = {
[SiaType.Int8]: "addInt8",
[SiaType.Int16]: "addInt16",
[SiaType.Int32]: "addInt32",
[SiaType.Int64]: "addInt64",
[SiaType.UInt8]: "addUInt8",
[SiaType.UInt16]: "addUInt16",
[SiaType.UInt32]: "addUInt32",
[SiaType.UInt64]: "addUInt64",
[SiaType.String]: "addStringN",
[SiaType.String8]: "addString8",
[SiaType.String16]: "addString16",
[SiaType.String32]: "addString32",
[SiaType.String64]: "addString64",
[SiaType.ByteArray8]: "addByteArray8",
[SiaType.ByteArray16]: "addByteArray16",
[SiaType.ByteArray32]: "addByteArray32",
[SiaType.ByteArray64]: "addByteArray64",
[SiaType.Bool]: "addBool",
[SiaType.BigInt]: "addBigInt",
[SiaType.Array8]: "addArray8",
[SiaType.Array16]: "addArray16",
[SiaType.Array32]: "addArray32",
[SiaType.Array64]: "addArray64",
};

export const siaTypeSerializerArrayItemMap: Record<SiaType, string> = {
[SiaType.Int8]: "serializeInt8ArrayItem",
[SiaType.Int16]: "serializeInt16ArrayItem",
[SiaType.Int32]: "serializeInt32ArrayItem",
[SiaType.Int64]: "serializeInt64ArrayItem",
[SiaType.UInt8]: "serializeUInt8ArrayItem",
[SiaType.UInt16]: "serializeUInt16ArrayItem",
[SiaType.UInt32]: "serializeUInt32ArrayItem",
[SiaType.UInt64]: "serializeUInt64ArrayItem",
[SiaType.String]: "serializeStringArrayItem",
[SiaType.String8]: "serializeString8ArrayItem",
[SiaType.String16]: "serializeString16ArrayItem",
[SiaType.String32]: "serializeString32ArrayItem",
[SiaType.String64]: "serializeString64ArrayItem",
[SiaType.ByteArray8]: "serializeByteArray8ArrayItem",
[SiaType.ByteArray16]: "serializeByteArray16ArrayItem",
[SiaType.ByteArray32]: "serializeByteArray32ArrayItem",
[SiaType.ByteArray64]: "serializeByteArray64ArrayItem",
[SiaType.Bool]: "serializeBoolArrayItem",
[SiaType.BigInt]: "serializeBigIntArrayItem",
[SiaType.Array8]: "serializeArray8ArrayItem",
[SiaType.Array16]: "serializeArray16ArrayItem",
[SiaType.Array32]: "serializeArray32ArrayItem",
[SiaType.Array64]: "serializeArray64ArrayItem",
};
Loading