diff --git a/library/browser/html.hexa b/library/browser/html.hexa index 293e31c..8b1a803 100644 --- a/library/browser/html.hexa +++ b/library/browser/html.hexa @@ -1,6 +1,6 @@ // The MIT License // -// Copyright (C) 2021-2023 Oleh Petrenko +// Copyright (C) 2021-2024 Oleh Petrenko // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -20,6 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +/// Global browser functions and values declare let window: { /// Raw global window object window: Any diff --git a/library/c/runtime.hexa b/library/c/runtime.hexa index 07ff098..21b62ea 100644 --- a/library/c/runtime.hexa +++ b/library/c/runtime.hexa @@ -1,6 +1,6 @@ // The MIT License // -// Copyright (C) 2022 Oleh Petrenko +// Copyright (C) 2022-2024 Oleh Petrenko // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,9 +26,10 @@ fun hexaRuntimeInit(): Void { - + // TODO } +// TODO description and documentation @struct class RuntimeAllocated { } diff --git a/library/c/string.hexa b/library/c/string.hexa index 39f88ee..e576699 100644 --- a/library/c/string.hexa +++ b/library/c/string.hexa @@ -154,7 +154,7 @@ class String { } static fun fromUTF8z(string: ConstArrayPointer): String { - // Note: must use own string length implementation cause incompatible with freestanding targets + // NOTE must use own string length implementation cause incompatible with freestanding targets let size: Int = countUTF8z(string) // TODO test type check that constructor is private // TODO use stack allocated array for small strings or .bss 64k one if size < 64k @@ -307,7 +307,7 @@ class String { static fun fromInt32(value: Int): String { // TODO just [0, ..., 0] N times - // Note: reserves 2 bytes for null-terminator + // NOTE reserves 2 bytes for null-terminator // ^ for some reason required despite being UInt16-array // TODO ^ test it more, comment/overwrite `bytes[i] = 0` etc var bytes: ArrayByValue = [0] diff --git a/library/nodejs/nodejs.hexa b/library/nodejs/nodejs.hexa index 267fbd0..97c6314 100644 --- a/library/nodejs/nodejs.hexa +++ b/library/nodejs/nodejs.hexa @@ -1,6 +1,6 @@ // The MIT License // -// Copyright (C) 2021-2023 Oleh Petrenko +// Copyright (C) 2021-2024 Oleh Petrenko // Copyright (C) 2018 Bogdan Danylchenko // // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -25,7 +25,7 @@ declare fun require(package: String): Any declare let __dirname: String declare let __filename: String -// TODO reqire(Buffer)? +// TODO reqire(Buffer)? node:Buffer `require('node:buffer').Buffer` @rename("Buffer") @native("Buffer") declare class Buffer { diff --git a/source/cli/init.hexa b/source/cli/init.hexa index fbc4f87..1df7848 100644 --- a/source/cli/init.hexa +++ b/source/cli/init.hexa @@ -163,5 +163,6 @@ fun init() { // Detects `y`, `yes` and empty answer as `true` fun isYes(answer: String): Bool { + // TODO code gen must cache this array globally for .includes without allocation return ['y','yes',''].includes(answer.toLowerCase().trim()) } diff --git a/source/compiler/lexer.hexa b/source/compiler/lexer.hexa index f22984c..68660fc 100644 --- a/source/compiler/lexer.hexa +++ b/source/compiler/lexer.hexa @@ -58,7 +58,7 @@ class Lexer { let meta: [Meta] = [] // ^ try the compressed idea for meta's at least TODO // TODO no zeroing of this buffer when parser is *non*-look-ahead - let tokens = Buffer.alloc(len + 1) // Note: 1 extra space for Token.Eof + let tokens = Buffer.alloc(len + 1) // NOTE 1 extra space for Token.Eof // TODO ensure optimizer/typer infers `Array` properly var lines = [] var columns = [] @@ -245,7 +245,7 @@ class Lexer { // Identifiers and keywords // A-z _ - // Note: non-ascii identifiers are NOT allowed + // NOTE non-ascii identifiers are NOT allowed // TODO describe the 95 trick if ((_8 & 95) >= 65 && (_8 & 95) <= 90) or (_8 == 95) { let title = _8 <= 90 @@ -254,7 +254,7 @@ class Lexer { // TODO is table lookup really faster than conditions? Bit mask possible> do { - // Note: underscore is inside keyword map + // NOTE underscore is inside keyword map // This excludes numbers allLowercase = allLowercase and (_8 >= 95) // TODO `'_'.charCodeAt(0)` p++ @@ -326,6 +326,7 @@ class Lexer { // >>> // TODO this may be done in parser + // ^ if lexer called from parser, it may set flag of not-parsing >>> in templates if _16 == 15934 and (get_8(position + 2) == ">".charCodeAt(0)) { add(Token.UnsignedRightShift) position += 3 diff --git a/source/compiler/normalizer.hexa b/source/compiler/normalizer.hexa index 42fdb4b..362926f 100644 --- a/source/compiler/normalizer.hexa +++ b/source/compiler/normalizer.hexa @@ -876,10 +876,12 @@ class Normalizer { case As(e, kind, t): switch kind { case Question: console.log('`as?` is not yet supported by normalizer, only `as!`') + // TODO error/implement case KNot: return Expression.UnsafeBitCast(nodeToExpression(e), typer.types.get(t)) case _: console.log('`as` is not yet supported by normalizer, only `as!`') + // TODO error/implement } case Is(e, t): diff --git a/source/compiler/parser.hexa b/source/compiler/parser.hexa index 4064b62..b6408cb 100644 --- a/source/compiler/parser.hexa +++ b/source/compiler/parser.hexa @@ -1902,7 +1902,7 @@ class Parser { let token = tok() if - // Note: don't do it like that! Some type syntax uses lowercases + // NOTE don't do it like that! Some type syntax uses lowercases //tok() != Token.Assign and //tok() != Token.CallClose and //tok() != Token.Comma diff --git a/source/compiler/preprocessor.hexa b/source/compiler/preprocessor.hexa index 0eac53f..d16d522 100644 --- a/source/compiler/preprocessor.hexa +++ b/source/compiler/preprocessor.hexa @@ -42,7 +42,7 @@ class Preprocessor { private static fun processTokens(tokens: Tokens, i: Int, project: Project): Tokens { var i = i var token = tokens.token[0] as! Token - let bytes = tokens.token.slice() // Note: this creates a copy with all tokens + let bytes = tokens.token.slice() // NOTE this creates a copy with all tokens // TODO Slicing from `i` would cause allocation on ~every array `[to]` insert, any ideas? // Maybe just allocate Array(len) + copy values upto i, so unused are null let params = tokens.value.slice() diff --git a/source/compiler/typer.hexa b/source/compiler/typer.hexa index dd0bcda..66aae51 100644 --- a/source/compiler/typer.hexa +++ b/source/compiler/typer.hexa @@ -2240,14 +2240,15 @@ class Typer { addScope(name, node) - // `a op b` like `a + b` + // `a = b` as a statement case Binop(a, op, b): fillExpression(node) var parent: Node = parents.get(a) // `a = b` // TODO separate assign node? or just nested pattern... - if op == Token.Assign { switch parent { + if op == Token.Assign { + switch parent { case null: switch a { case Ident(_): // Ok @@ -2994,26 +2995,26 @@ class Typer { // TODO why the heck `.Vname` here gives Ln1, Col 12??? // type.V here is ok, but is in the string interpolator // ^ should be possible to set starting col/line in Lexer - // Note: `proposeSimilar` is useless for DotUpper over instances + // NOTE `proposeSimilar` is useless for DotUpper over instances fail('Enum `\(type.name)` instance has no field `.\(n)`', node) case ClassInstance(type): failNonFatal('Type `\(type.name)` is defined here', type.parent) - // Note: `proposeSimilar` is useless for DotUpper over instances + // NOTE `proposeSimilar` is useless for DotUpper over instances fail('Class `\(type.name)` has no field `.\(n)`\n\nNote that you are trying to access plain `class` instance and not `enum`', node) case Class(type): failNonFatal('Type `\(type.name)` is defined here', type.parent) - // Note: `proposeSimilar` is useless for DotUpper over classes + // NOTE `proposeSimilar` is useless for DotUpper over classes fail('Class `\(type.name)` has no field `.\(n)`\n\nNote that you are trying to access `class` and not `enum`', node) case Enum(type): let index = type.fieldNames.indexOf(n) // TODO `@lazy let enumName = getName(type.name)` so no need to place in every failing `if` if index < 0 { failNonFatal('Type `\(type.name)` is defined here', type.parent) - // Note: `proposeSimilar` but only constructors (if any) + // NOTE `proposeSimilar` but only constructors (if any) fail('Enum `\(type.name)` has no value constructor `.\(n)`\n' + proposeSimilar(type.fieldNames.filter((element, index) => type.fieldEnumConstructor[index]), n, 'constructors'), node) } if type.fieldEnumConstructor[index] != true { - // Note: this case is probably impossible, i.e. .N *not* being constructor (than what?) + // NOTE this case is probably impossible, i.e. .N *not* being constructor (than what?) fail('Enum `\(type.name)` field `.\(n)` is not a value constructor', node) } if let fieldType = type.fieldType[index] { @@ -3033,6 +3034,7 @@ class Typer { if asValue { fail('Cannot use type `\(name)` as a value, use `\(name)()` to call constructor', node) } + let subj = find(name) if subj == null { fail('Cannot find type with name `\(name)`', node) @@ -3050,7 +3052,8 @@ class Typer { let mod = currentModule registerClassType(subj) currentModule = mod - case Enum(_): registerEnumType(subj) + case Enum(_): + registerEnumType(subj) } if let type = types.get(subj) { @@ -3465,6 +3468,7 @@ class Typer { // TODO `null == null` should error cause no sense if leftString != 'null', rightString != 'null' { + // TODO recommend `.address` for pointers fail('Operator `a \(tokenString) b` requires `a` and `b` of comparable types, but got `\(leftString)` and `\(rightString)`', b) } } @@ -3773,8 +3777,9 @@ class Typer { } if thisType == null { - fail('Cannot access `this` in class method', node) + fail('Cannot access `this` in the static method', node) } + types.set(node, thisType) parents.set(node, thisNode) @@ -3784,6 +3789,7 @@ class Typer { // `return e` case Return(e): + // TODO cannot return from constructor switch e { case Var(name, _, _, const): let prefix = const? 'let' : 'var' diff --git a/source/data/data.hexa b/source/data/data.hexa index ca19990..d8dcbf5 100644 --- a/source/data/data.hexa +++ b/source/data/data.hexa @@ -101,15 +101,15 @@ enum Node { /// `declare fun name(vars) retType { body }` // Name is `new` for constructor // TODO expr Node.Block (goal is *not* to `Node extends NodeBlock` but to actually limit tags) - Function(name String?, body Node, vars [Node], retType NodeType, external Bool, variadic Bool) + Function(name String?, body Node, vars [Node], returnType NodeType, external Bool, variadic Bool) - /// (vars) retType => expr + /// `(vars) retType => expr` // TODO parser `: retType` is really needed at all? Arrow(expr Node, vars [Node], retType NodeType) - /// [external ? declare] (const ? let : var) name nodeType [= expr] // `varStatic` =>> `funStatic` `varPrivate` etc + /// [external ? `declare`] (const ? `let` : `var`) `name nodeType` [`= expr`] // TODO `expr Node?` Var(name String, varType NodeType, expr Node, const Bool, external Bool) @@ -124,9 +124,11 @@ enum Node { Try(expr Node, t [NodeType], v [Node], catches [Node]) /// `expr.name` + // TODO rename to Field Dot(expr Node, name String) /// expr.Name + // TODO rename to CapitalField DotUpper(expr Node, name String) /// `new T { } (args)` TODO new syntax @@ -178,20 +180,23 @@ enum Node { Underscore /// `...` + // TODO support `...expr` Interval /// `static` field + // TODO drop this Static(field Node) /// `private` field or type + // TODO drop this Private(field Node) /// for name in over by /// for name in over ... range by For(name String, over Node, by Node, range Node) - /// `nullable ?? othewise` - Elvis(nullable Node, otherwise Node) + /// `nullable ?? alternative` + Elvis(nullable Node, alternative Node) /// `T` but as expression NodeTypeValue(type NodeType) diff --git a/source/data/nice.hexa b/source/data/nice.hexa index d484aa2..4b3cee3 100644 --- a/source/data/nice.hexa +++ b/source/data/nice.hexa @@ -60,6 +60,7 @@ enum Statement { Assignop(name Expression, op Token, value Expression) // TODO ^ `AssignOp` For(name String, over Expression, by Statement) + // TODO why not separate `DoWhile`? While(econd Expression, e Statement, pre Bool) Increment(e Expression) Decrement(e Expression) diff --git a/source/data/token.hexa b/source/data/token.hexa index 7110bb9..64a845e 100644 --- a/source/data/token.hexa +++ b/source/data/token.hexa @@ -98,7 +98,7 @@ enum Token : Int { BitwiseNot = 88 // ~ // Binary - // TODO Note: Op- prefix for names used cause in IR binary operators use Token as operator kind + // TODO NOTE Op- prefix for names used cause in IR binary operators use Token as operator kind // ^ somehow create an enum subset of them? RightArrow = 90 // => Assign = 91 // = @@ -155,7 +155,7 @@ enum Token : Int { case KElse: return "else" case KEnum: return "enum" case KExtends: return "extends" - // Note: `declare` instantly creates TypeScript vibe and must be kept + // NOTE `declare` instantly creates TypeScript vibe and must be kept case KDeclare: return "declare" case KFalse: return "false" case KFor: return "for" diff --git a/source/main.hexa b/source/main.hexa index 17da6af..4d9166a 100644 --- a/source/main.hexa +++ b/source/main.hexa @@ -151,7 +151,7 @@ class Main { if named { let name = DataHelper.nameOf(e) - if (project.globals.has(name)) { + if project.globals.has(name) { let data = project.data.get(e) let already = project.data.get(project.globals.get(name)) let msg = "Global node `\(name)` declared in `\(path)` already defined at `\(already.fileName)` line `\(already.line)`" @@ -619,7 +619,7 @@ class Main { console.log("[Building \(input.name)]") } - console.log("[Using 1 of \(require('os').cpus().length) CPU cores]") + console.log("[Using 1 of \(require('os').cpus().length) CPU threads]") // TODO ^ fix syntax highlighting for \parenthesis pairs } } diff --git a/source/targets/genC.hexa b/source/targets/genC.hexa index 98f299f..38bc72b 100644 --- a/source/targets/genC.hexa +++ b/source/targets/genC.hexa @@ -32,6 +32,7 @@ class GenCxx { fun perform(normalizer, target: String, options: [String]): String { project = normalizer extraUnderscore = options.includes('extraUnderscore') + // TODO report unsupported options return stringify(target) } @@ -113,10 +114,12 @@ class GenCxx { // No need to output simple enum values // TODO proper base type forward.push('struct ' + e.name + '_;') - if (e.staticVars.length + e.staticMethods.length == 0) { + if e.staticVars.length + e.staticMethods.length == 0 { continue } + // TODO tdef C* C + // TODO this seem to be a leftover from C++ types.push('struct ' + e.name + '_ {\n\t') // Static vars before static functions @@ -322,6 +325,7 @@ class GenCxx { if isPacked { types.push('#pragma pack(1)\n') } + types.push(nativeKind + c.name + '_ {\n\t') let vtable = ['struct ' + c.name + '__ {\n\t'] // TODO const pointer to const struct @@ -608,7 +612,7 @@ class GenCxx { customHeader = link.customHeader } - // Note: before `dllExports.push` + // NOTE before `dllExports.push` if let rename = link.rename { name = rename } @@ -751,6 +755,7 @@ class GenCxx { if value != '(int32_t)0' { out.push('\t' + name + '_ = ' + value + ';\n') } + // TODO init them at declaration! int a = 123; } } //out.push('\n\tvar ' + name) @@ -772,11 +777,11 @@ class GenCxx { } let init = printStatement(project.init[0]) - // Note: strings should be gathered after ALL expressions printed + // NOTE strings should be gathered after ALL expressions printed // TODO may be [] length == 0 let strings: [String] = ['\tString_$root_ = String_$new_();\n'] for id in declarationsOfStrings.length { - // Note: `const char[]` causes compiler to make a copy of the entire string on every usage + // NOTE `const char[]` causes compiler to make a copy of the entire string on every usage // TODO set ref counting //strings.push('\tString_Strings[\(id)] = String_fromUTF8z("\(declarationsOfStrings[id])");\n') strings.push('\tString_\(id) = String_$fromUTF16z_((const uint16_t*)String_\(id)_);\n') @@ -1112,6 +1117,7 @@ class GenCxx { if generics[0] == project.typer.typeUInt8 { return stringifyType(valueType) + ' ' + name + '_' + arraySize + ' = "' + string + '"' } + if generics[0] == project.typer.typeUInt16 { return stringifyType(valueType) + ' ' + name + '_' + arraySize + ' = L"' + string + '"' } @@ -1535,7 +1541,7 @@ class GenCxx { return '%printNullableToValueConverter%' } - /// Note: this is a strict `as!` kind of conversion + /// NOTE this is a strict `as!` kind of conversion fun printTypeConverter(string: String, fromValue: Type, to: Type): String { if fromValue == to { return string @@ -1738,7 +1744,7 @@ class GenCxx { (fromValue == project.typer.typeNullFloat32 and to == project.typer.typeFloat32) { return string + '.value_' - // Note: no need to validate `has_` cause `null => has_ == 0 and value == 0` + // NOTE no need to validate `has_` cause `null => has_ == 0 and value == 0` } return string + '/*T = T?*/' return '%T = T?%' diff --git a/source/targets/genNasm.hexa b/source/targets/genNasm.hexa index 7c29748..85a34ef 100644 --- a/source/targets/genNasm.hexa +++ b/source/targets/genNasm.hexa @@ -154,7 +154,7 @@ class NasmFunction { } else if stackStorage != 0 { body.unshift('sub RSP, \(stackStorage)') } - body.unshift('push RBP; Set stack frame') // Note: `unshift` works in reverse order + body.unshift('push RBP; Set stack frame') // NOTE `unshift` works in reverse order // TODO add ret only if not done } @@ -881,7 +881,7 @@ class GenNasm { let typeStrings: [Type : String] = [:] - // Note: returns with ending space + // NOTE returns with ending space fun typeToString(type: Type): String { if let string = typeStrings.get(type) { return string @@ -1089,7 +1089,7 @@ class GenNasm { if asC { // TODO mirror \n \t etc dataSection.push('static const wchar_t *String\(id) = L"\(text)";') - // Note: `const char[]` causes compiler to make a copy of the entire string on every usage + // NOTE `const char[]` causes compiler to make a copy of the entire string on every usage bssSection.push("static struct String_* String$\(id);") } else { dataSection.push("String.\(id) dw __utf16le__('\(text)'), 0") diff --git a/source/tests/testTyper.hexa b/source/tests/testTyper.hexa index 363bee0..e2721e0 100644 --- a/source/tests/testTyper.hexa +++ b/source/tests/testTyper.hexa @@ -398,6 +398,10 @@ class TestTyper { shouldNotError('var x = 0 var z = x += 0 z = 0') shouldError('var x = 0 var z = x += 0 z = true') + // `shouldError('[var/let] a = []')` // `[]` may be Map or Array or keep `[:]` + // ^ must error at `[]` node itself when fail to infer its type + // same for generic args `fun (generic)` TODO + // Typing is shouldNotError('let t = 1 t is Int') shouldError('let t = 1 t is Any') @@ -445,6 +449,7 @@ class TestTyper { shouldError("declare fun f()") shouldNotError("declare fun f(): Int") shouldError("var a = declare fun f(): Int") + // TODO `declare A = A` some recursion, A=B, B=A etc, also Int=A // Decorators shouldNotError('@att("value") 123')