diff --git a/docs/target-haxe.md b/docs/target-haxe.md deleted file mode 100644 index 089ad19..0000000 --- a/docs/target-haxe.md +++ /dev/null @@ -1,9 +0,0 @@ -# Haxe Target - -Target for [H*a*xe](https://en.wikipedia.org/wiki/Haxe) of [haxe.org](https://haxe.org) language. - -## Tasks - -- [ ] Fix types -- [ ] Add missing features -- [ ] Bootstrap compiler over Haxe->JavaScript (if possible?) diff --git a/library/haxe/haxe.hexa b/library/haxe/haxe.hexa deleted file mode 100644 index 5c89c67..0000000 --- a/library/haxe/haxe.hexa +++ /dev/null @@ -1,208 +0,0 @@ -// The MIT License -// -// Copyright (C) 2021-2022 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 -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Basic - -declare class Void {} -declare class Any {} -declare class Int {} -declare class Float {} -declare class Bool {} - -declare class String { - let length: Int - fun toUpperCase(): String - fun toLowerCase(): String - fun endsWith(str: String): Bool - fun startsWith(str: String): Bool - fun charAt(index: Int): String - fun indexOf(str: String, startIndex: Int?): Int - fun lastIndexOf(str: String, startIndex: Int?): Int - fun split(delimiter: String): [String] - fun toString(): String - fun substring(startIndex: Int, endIndex: Int?): String - static fun fromCharCode(code: Int): String - fun charCodeAt(index: Int): Int? - fun trim(): String - fun substr(pos: Int, len: Int?): String -} - -declare class Array { - let length: Int - fun concat(a: [T]): [T] - fun join(sep: String): String - fun pop(): T? - fun push(x: T): Int - fun includes(x: T): Bool - fun reverse(): Void - fun shift(): T? - fun slice(pos: Int, end: Int?): [T] - fun sort(f: (T, T)=>Int): Void - fun splice(pos: Int, len: Int): [T] - fun toString(): String - fun unshift(x: T): Void - fun indexOf(x: T, fromIndex: Int?): Int - fun lastIndexOf(x: T, fromIndex: Int?): Int - fun filter(f: T=>Bool): [T] - fun map(f: T=>T): [T] - fun reduce(f: (accumulator: T, currentValue: T)=>T): T - fun copyWithin(target: Int, start: Int?, end: Int?): [T] - fun fill(value: T, start: Int, end: Int): [T] -} - -declare class Map { - new () - fun get(k: K): V - fun set(k: K, v: V): Void - fun has(k: K): Bool - fun keys(): [K] -} - -// Extra - -declare class Console { - fun log(str: String): Void - fun trace(str: String): Void - fun error(data: Any, message: String?): Void -} - -declare let console: Console - -declare class JSON { - static fun parse(text: String): Any - static fun stringify(value: Any, replacer: (Any, Any)=>Any?, space: String?): String -} - -declare class Math { - static fun abs(v: Float): Float - static fun acos(v: Float): Float - static fun asin(v: Float): Float - static fun atan(v: Float): Float - static fun atan2(y: Float, x: Float): Float - static fun ceil(v: Float): Int - static fun cos(v: Float): Float - static fun exp(v: Float): Float - static fun floor(v: Float): Int - static fun log(v: Float): Float - static fun max(a: Float, b: Float): Float - static fun min(a: Float, b: Float): Float - static fun pow(v: Float, exp: Float): Float - static fun random(): Float - static fun round(v: Float): Int - static fun sin(v: Float): Float - static fun sqrt(v: Float): Float - static fun tan(v: Float): Float -} - -declare class Buffer /*implements ArrayAccess*/ { - static fun alloc/**/(size: Int): Buffer - let length: Int - let buffer: ArrayBuffer - new (bufsize: Int) - fun slice(offset: Int): Buffer - @indexSet(value, key) - fun writeUInt8(value: Int, offset: Int): Int - fun writeUInt16LE(value: Int, offset: Int): Int - fun writeUInt32LE(value: Int, offset: Int): Int - fun writeDoubleLE(value: Float, offset: Int): Int - fun write(string: String, offset: Int, encoding: String): Int - @indexGet - fun readUInt8(offset: Int): Int - fun readUInt16LE(offset: Int): Int - fun readUInt32LE(offset: Int): Int - fun toString(encoding: String, start: Int?, end: Int?): String - static fun from/**/(string: String, encoding: String?): Buffer -} - -declare class ArrayBuffer {} - -declare class Fs { - static fun writeFileSync(path: String, data: String): Void - static fun readdirSync(path: String): [String] - static fun readFileSync(path: String): Buffer - static fun lstatSync(path: String): Any - static fun existsSync(path: String): Bool - static fun mkdirSync(path: String): Void - static fun readSync(fd: Int, buffer: Buffer, offset: Int, length: Int, position: Int): Int -} - -declare class Path { - static let sep: String - static fun resolve(path: String): String - static fun parse(path: String): ParsedPath - static fun join(...path: String): String -} - -declare class ParsedPath { - var root: String - var dir: String - var base: String - var ext: String - var name: String -} - -declare class Process { - static let stdin: ProcessStd - static let stdout: ProcessStd - static let stderr: ProcessStd - static let argv: [String] - @haltsProgram - static fun exit(errorCode: Int): Void - static let versions: { node: String } - fun cwd(): String - let env: Any -} - -declare class ProcessStd { - fun write(text: String): Void - fun once(name: String, callback: ()=>Void): Void - let fd: Any -} - -declare fun parseInt(text: String): Int -declare let __dirname: String -declare let process: ProcessModule -declare fun eval(code: String): Any - -declare class Date { - static fun now(): Float -} - -declare class Reflect { - static fun has(object: Any, name: String): Bool - static fun get(object: Any, name: String): Any? - static fun set(object: Any, name: String, value: Any?): Bool - static fun ownKeys(object: Any): [String] -} - -declare class ProcessModule { - let stdin: ProcessStd - let stdout: ProcessStd - let stderr: ProcessStd - let argv: [String] - @haltsProgram - fun exit(errorCode: Int): Void - fun cwd(): String - let versions: { node: String } // todo not require value = for lets in declare - let env: Any // todo not require value = for lets in declare - let platform: String -} diff --git a/source/server/format.hexa b/source/server/format.hexa index c473167..0fa4e8b 100644 --- a/source/server/format.hexa +++ b/source/server/format.hexa @@ -32,7 +32,7 @@ fun autoFormatWholeFile(file: String): String { var tabStack = [''] var tabCase = [false] var depth = 0 - let assignOp = [Token.Add, Token.Multiply, Token.Subtract] + let assignOp = [Token.Add, Token.Multiply, Token.Subtract, Token.BitwiseAnd, Token.BitwiseOr] var parenthesis = -1000000 fun updateTab() { @@ -124,26 +124,42 @@ fun autoFormatWholeFile(file: String): String { lastToken == Token.Dot or token == Token.Dot or + // `+=` (token == Token.Assign and assignOp.includes(lastToken)) or + // `~123` + lastToken == Token.BitwiseNot or + // `(something` lastToken == Token.CallOpen or // `(` ( token == Token.CallOpen and ( + // Keywords lastToken != Token.KIn and - lastToken != Token.Add and - lastToken != Token.Subtract and lastToken != Token.KReturn and lastToken != Token.KIf and lastToken != Token.KFun and - lastToken != Token.LogicalAnd and - lastToken != Token.LogicalOr and lastToken != Token.KNew and lastToken != Token.KNot and lastToken != Token.KSwitch and + lastToken != Token.KWhile and + lastToken != Token.KDo and + lastToken != Token.KFor and + lastToken != Token.LogicalAnd and + lastToken != Token.LogicalOr and + + // Operators lastToken != Token.Assign and + lastToken != Token.Add and + lastToken != Token.Subtract and + lastToken != Token.BitwiseAnd and + lastToken != Token.BitwiseOr and + lastToken != Token.Comma and + lastToken != Token.Equal and + lastToken != Token.Unequal and + lastToken != Token.Question and // `@demo()` but not `@demo ()` not ( @@ -158,7 +174,7 @@ fun autoFormatWholeFile(file: String): String { // @sds() TODO error () no args not allowed token == Token.CallClose or - // `[]` + // `[` lastToken == Token.IndexOpen or ( token == Token.IndexOpen and diff --git a/source/targets/genC.hexa b/source/targets/genC.hexa index 34f6cd5..e8ffbdf 100644 --- a/source/targets/genC.hexa +++ b/source/targets/genC.hexa @@ -881,7 +881,7 @@ class GenCxx { if c.external { if c.jsRequire != null { // todo MAKE IT possible to use plain-c include's! - // like "declare" vs "deep extern declare" for Haxe + // like "declare" vs "deep extern declare" out += '\n ' + '/*var ' + c.name + ' = require("' + c.jsRequire + '")*/' continue } diff --git a/source/targets/genCxx.hexa b/source/targets/genCxx.hexa index b2d7290..30ab634 100644 --- a/source/targets/genCxx.hexa +++ b/source/targets/genCxx.hexa @@ -443,7 +443,7 @@ if (c.external) { if (c.jsRequire != null) { // todo MAKE IT possible to use plain-c include's! - // like "declare" vs "deep extern declare" for Haxe + // like "declare" vs "deep extern declare" out += '\n ' + '/*var ' + c.name + ' = require("' + c.jsRequire + '")*/' continue } diff --git a/source/targets/genHaxe.hexa b/source/targets/genHaxe.hexa deleted file mode 100644 index 9605300..0000000 --- a/source/targets/genHaxe.hexa +++ /dev/null @@ -1,429 +0,0 @@ -// The Hexa Compiler -// Copyright (C) 2018 Oleh Petrenko -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, version 3 of the License. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see . - -// Generates Haxe https://haxe.org -// TODO haxe4 mode -class GenHaxe { - new () {} - - var project: NiceProject - let extension = '.hx' - let nativeEnums = true - - static fun spawn() { - return new GenHaxe() - } - - fun perform(normalizer): String { - project = normalizer - return stringify() - } - - fun stringify() { - var out = 'package hexa;\n\nusing StringTools;\n' - - // Types - for (e in project.enumsSimple) { - // TODO (Dynamic) to type - out += '\n' + '@:enum abstract ' + e.name + '(Dynamic) {' - for (v in e.names.length) { - // TODO auto-fill empty values in normalizer - out += '\n\tvar ' + e.names[v] + ' = ' + printExpression(e.values[v] ?? Expression.Int(v)) + ';' - } - for (v in e.staticVars) switch v { - case Var(name, expr, type): - out += '\n\t' + e.name + '.' + name - if (expr != null) out += ' = ' + printExpression(expr) - case Const(name, expr, type): - out += '\n\t' + e.name + '.' + name - out += ' = ' + printExpression(expr) - } - for (v in e.staticMethods) switch v { - // TODO - //case Function(name, expr, args, defaults, types, returns): - // out += '\n\tpublic static function ' + name - // out += printFunctionArguments(args, defaults, types) + printType(returns) - // out += ' ' + printBlock(expr) + ';' - } - out += '\n}\n' - } - - for (e in project.enumsComplex) { - out += '\n' + 'enum ' + e.name + ' {' - var i = 0 - for (name in e.names) { - out += '\n\t' + name - if (e.constructors[i] != null) { - out += '(' - out += [for (k in e.constructors[i].length) { - e.constructors[i][k] + printNodeAsType(e.types[i][k], ': ') - }].join(', ') - out += ');' - } else out += ';' - i++ - } - out += '\n}\n' - } - - for (i in project.interfaces) { - throw i - } - - for (c in project.classes) { - if (c.external) { - if (c.jsRequire != null) { - continue - } - continue - } - - out += '\n' + 'class ' + c.name - if (let params = c.genericParams) out += '<' + params.join(', ') + '>' - if (let implement = c.implement) out += ' implements ' + implement - if (let params = c.implementParams) out += '<' + params.join(', ') + '>' - out += ' {' - for (v in c.vars) switch v { - case Var(name, expr, type): - out += '\n\tpublic var ' + name + printType(type) - if (expr != null) out += ' = ' + printExpression(expr) - out += ';' - case Const(name, expr, type): - out += '\n\tpublic var ' + name + printType(type) + ' = ' + printExpression(expr) + ';' - } - - // TODO hint `switch v {}` switch does nothing - for (v in c.methods) switch v { - // TODO - //case Function(name, expr, args, defaults, types, returns): - //if (name == null || name == 'new') out += '\n\tpublic function new' - //else out += '\n\tpublic function ' + name - //out += printFunctionArguments(args, defaults, types) - //if (name != null && name != 'new') out += printType(returns) - //out += ' ' + printBlock(expr) + ';' - } - - for (v in c.staticVars) switch v { - case Var(name, expr, type): - out += '\n\tpublic static var ' + name + printType(type) - if (expr != null) out += ' = ' + printExpression(expr) - out += ';' - case Const(name, expr, type): - out += '\n\tpublic static var ' + name + printType(type) - out += ' = ' + printExpression(expr) + ';' - } - - for (v in c.staticMethods) switch v { - // TODO - //case Function(name, expr, args, defaults, types, returns): - // out += '\n\tpublic static function ' + name - // out += printFunctionArguments(args, defaults, types) + printType(returns) - // out += ' ' + printBlock(expr) + ';' - } - - out += '\n}\n' - } - - let globals: [String] = [] - - for (g in project.globalFuncs) switch g { - // TODO - //case Function(name, expr, args, defaults, types, returns): - // globals.push('\n\tpublic static function ' + name) - // globals.push(printFunctionArguments(args, defaults, types) + printType(returns)) - // globals.push(' ' + printBlock(expr) + ';') - } - - for (g in project.globalVars) switch g { - case Var(name, expr, type): - globals.push('\n\tpublic static var ' + name + printType(type)) - if (expr != null) - globals.push(' = ' + printExpression(expr)) - globals.push(';') - case Const(name, expr, type): - globals.push('\n\tpublic static var ' + name + printType(type)) - globals.push(' = ' + printExpression(expr) + ';') - } - - // Init - out += 'class HexaHaxe {\n\tpublic static function main() {' - tabs = '\t\t\t' - for (init in project.init) { - out += '\n\t\t{\n\t\t\t' - out += printStatement(init) - out += '\n\t\t}' - } - - out += '\n\t}' - - for g in globals { - out += g - } - - return out + '\n}' - } - - var tabs = '\t' - @inline fun pushTab() tabs += '\t' - @inline fun popTab() tabs = tabs.substring(0, tabs.length - 1) - - let reserved = ['with', 'var', 'instanceof', 'typeof', 'delete', 'undefined', 'package'] - let reservedGlobals = ['HexaHaxe'] - let globalAccessor = 'HexaHaxe.' - - // Surrounds with { brackets } single statement - fun printBlock(s: Statement): String { - switch s { - case Block(el): - if (el.length == 1) return '{ ' + printStatement(el[0]) + '; }' - if (el.length == 0) return '{}' - return printStatement(s) - case _: return '{ ' + printStatement(s) + '; }' - } - } - - fun printStatement(s: Statement) { - switch s { - case Statements(els): - var r = '' - for (s in els) if (s != null) r += '\n' + tabs + printStatement(s) + ';' - return r - - case Break: return 'break' - case Continue: return 'continue' - case Block(el): - pushTab() - var r = '{' - - for (e in el) switch e { - case null: - case Statements(els): - for (s in els) if (s != null) r += '\n' + tabs + printStatement(s) + ';' - case _: - r += '\n' + tabs + printStatement(e) + ';' - } - - popTab() - return r + '\n' + tabs + '}' - case New(e, args): return 'new ' + printExpression(e) + printCallArguments(args) - case Const(name, expr, type): return 'var ' + name + printType(type) + (expr == null? '' : ' = ' + printExpression(expr)) - case Var(name, expr, type): return 'var ' + name + printType(type) + (expr == null? '' : ' = ' + printExpression(expr)) - //case Function(name, expr, args, defaults, types, returns): - // return 'function ' + name + printFunctionArguments(args, defaults, types) + printType(returns) + ' ' + printBlock(expr) - case Return(e): - if (e == null) return 'return' - return 'return ' + printExpression(e) - case If(econd, eif, eelse): - var r = 'if (' + printExpression(econd) + ') ' + printBlock(eif) - if (eelse != null) r += ' else ' + printStatement(eelse) - return r - case Call(e, args): return printExpression(e) + printCallArguments(args) - case Try(expr, t, v, catches): - var r = 'try ' - r += printStatement(expr) - r += ' catch (' + v[0] + (printType(t[0]) || ': Dynamic') + ') ' - r += printStatement(catches[0]) - return r - case Assign(a, v): - return printExpression(a) + ' = ' + printExpression(v) - case Throw(e): - return 'throw ' + printExpression(e) - case For(name, over, by): - return 'for (' + name + ' in ' + printExpression(over) + ') ' + printStatement(by) - case Increment(e): return printExpression(e) + '++' - case Decrement(e): return printExpression(e) + '--' - case While(econd, e, pre): - if (pre) return 'while (' + printExpression(econd) + ') ' + printStatement(e) - return 'do ' + printStatement(e) + ' while (' + printExpression(econd) + ')' - case Assignop(a, op, value): - return printExpression(a) + ' ' + Token.stringify(op) + '= ' + printExpression(value) - case Dot(expr, name): return printExpression(expr) + '.' + name - - case Switch(expr, cases, statements): - var r = 'switch (' + printExpression(expr) + ') {' - var hasDefault = false - - // case 1: case 2: case 3: - for (i in cases.length) if (cases[i].length > 0) { - r += '\n' + tabs + 'case ' - r += [for (cc in cases[i]) printExpression(cc)].join(', ') - r += ': ' + printStatement(statements[i]) + ';\n' + tabs - } - - for (i in cases.length) for (cc in cases[i]) switch cc { - case Underscore(_): hasDefault = true - } - - // default: - if not hasDefault for (i in cases.length) if (cases[i].length == 0) { - r += '\n' + tabs + 'default: ' + printStatement(statements[i]) + ';' - r += '\n' + tabs - hasDefault = true - } - - if not hasDefault { - r += '\n' + tabs + 'default: {};' - r += '\n' + tabs - } - - return r + '}' - - case _: console.error("Unknown statement kind:", (s??[])[0]) - } - - return '{/**/}' - } - - fun printCallArguments(args: [Expression]) { - return '(' + [for (a in args) printExpression(a)].join(', ') + ')' - } - - fun printFunctionArguments(args: [String], defaults: [Expression], types) { - return '(' + [for (a in args.length) - args[a] + printType(types[a]) + ((defaults != null && defaults[a] != null)? ' = ' + printExpression(defaults[a]) : '') - ].join(', ') + ')' - } - - fun stringType(t: NodeType, prefix: Bool) { - let prefix = prefix? ': ' : '' - if (t == null) return '' - if (t == null) return prefix + 'Dynamic' - - switch t { - case NodeType.ParametricType(name, params): - if (name == 'Buffer') return prefix + name - return prefix + name + '<' + [for (param in (params ?? [])) stringType(param, false)].join(', ') + '>' - case NodeType.Type(name): - if (name == 'Any') return prefix + 'Dynamic' - return prefix + name - case NodeType.Object(_): - return prefix + '{}' - case NodeType.Optional(t): - return prefix + 'Null<' + stringType(t, false) + '>' - } - - return prefix + 'Dynamic' - } - - fun printType(t: NodeType) { - let type = stringType(t, true) - if (type == ': Array') return '' - return type - } - - fun printNodeAsType(t: Node, prefix: String) { - switch t { - case Ident(name): return prefix + name - case Array(el): return prefix + 'Array<' + printNodeAsType(el[0], '') + '>' - - case null: return prefix + 'Dynamic' - case _: return prefix + 'Dynamic' - } - } - - fun printExpression(e: Expression) { - switch e { - case Null: return 'null' - case This: return 'this' - case Ident(name): return name - case Int(v): return '' + v - case Float(v): return '' + v - case String(s): - - let s = s.split('') - let charsOut = [] - while s.length > 0 { - switch s[0] { - case "$": - charsOut.push("$") - charsOut.push("$") - s.shift() - case "'": - charsOut.push("\\") - charsOut.push("'") - s.shift() - case "\n": - charsOut.push("\\n") - s.shift() - case "\r": - charsOut.push("\\r") - s.shift() - case "\\": - s.shift() - if (s[0] == "'") { - charsOut.push("\\") - charsOut.push("'") - s.shift() - } else { - charsOut.push('\\') - } - case _: - charsOut.push(s[0]) - s.shift() - } - } - - return "'" + charsOut.join('') + "'" - case True: return 'true' - case False: return 'false' - case Dot(expr, name): return printExpression(expr) + '.' + name - case Call(e, args): return printExpression(e) + printCallArguments(args) - case Function(name, expr, args, defaults, funcType): - let name = name ?? '' - let returns = project.typer.typeVoid // TODO - let types = [] // TODO - return 'function ' + name + printFunctionArguments(args, defaults, types) + printType(returns) + ' ' + printBlock(expr) - case Arrow(expr, args, defaults, types, returns): - return 'function ' + printFunctionArguments(args, defaults, types) + printType(returns) + ' return ' + printExpression(expr) - case New(e, args): return 'new ' + printExpression(e) + printCallArguments(args) - case Array(el): return '[' + [for (a in el) printExpression(a)].join(', ') + ']' - case Unop(op, postfix, e): - if (postfix) return printExpression(e) + Token.stringify(op) - return Token.stringify(op) + printExpression(e) - case Elvis(nullable, othewise): - return '(function(){var _ = ' + printExpression(nullable) + '; if (_ != null) return _; return ' + printExpression(othewise) + ';}())' - case Parenthesis(e): return '(' + printExpression(e) + ')' - case Binop(a, op, b): - return printExpression(a) + ' ' + Token.stringify(op) + ' ' + printExpression(b) - case Index(expr, index): - return printExpression(expr) + '[' + printExpression(index) + ']' - case If(econd, eif, eelse): - var r = '' - r += '(' + printExpression(econd) + ')?' - r += ' (' + printExpression(eif) + ')' - r += ' : ' + printExpression(eelse) - return r - case Object(names, el): - return '{' + [for (i in el.length) ((names[i]) + ':' + printExpression(el[i]))].join(', ') + '}' - case Map(keys, values): - if (keys.length == 0) return 'new Map()' - return '[' + - [for (i in keys.length) printExpression(keys[i]) + ' => ' + printExpression(values[i])].join(', ') - + ']' - case Assignop(a, op, value): - return printExpression(a) + ' ' + Token.stringify(op) + '= ' + printExpression(value) - case NativeOperator(kind, args, s): switch kind { - case Infix: return '((' + printExpression(args[0]) + ') ' + s + ' (' + printExpression(args[1]) + '))' - case Function: return s + printCallArguments(args) - case Prefix: return '(' + s + '(' + printExpression(args[0]) + '))' - case Postfix: return '((' + printExpression(args[1]) + ')' + s + ')' - } - case Underscore: return '_' - case _: - console.error("Unknown expression kind:", (e??[])[0], e) - } - - return '{/**/}' - } -}