diff --git a/.gitignore b/.gitignore index e3989be..8761f11 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,12 @@ build/ _test_tmp_pkg/ test_pkg/ examples_pkg/ + +# Temporary test directories +_test_*/ + +# Backup files +*.bak + +# Log files +*.log diff --git a/_test_array/bux.toml b/_test_array/bux.toml deleted file mode 100644 index ca1e559..0000000 --- a/_test_array/bux.toml +++ /dev/null @@ -1,2 +0,0 @@ -name = "test_array" -version = "0.1.0" diff --git a/_test_array/src/Main.bux b/_test_array/src/Main.bux deleted file mode 100644 index ab581e0..0000000 --- a/_test_array/src/Main.bux +++ /dev/null @@ -1,33 +0,0 @@ -module Main { -import Std::Array::Array; -import Std::Iter::Iter; -import Std::Test::Test; -import Std::Io::Io; - -func Main() -> int { - var arr: Array = Array_New(4); - Array_Push(&arr, 10); - Array_Push(&arr, 20); - Array_Push(&arr, 30); - - Test_AssertEqInt(Array_Len(&arr) as int, 3); - Test_AssertEqInt(Array_Get(&arr, 0), 10); - Test_AssertEqInt(Array_Get(&arr, 1), 20); - Test_AssertEqInt(Array_Get(&arr, 2), 30); - - var it: Iter = Array_Iter(&arr); - Test_AssertTrue(Iter_HasNext(&it)); - Test_AssertEqInt(Iter_Next(&it), 10); - Test_AssertEqInt(Iter_Next(&it), 20); - Test_AssertEqInt(Iter_Next(&it), 30); - Test_AssertFalse(Iter_HasNext(&it)); - - var it2: Iter = Array_Iter(&arr); - let count: uint = Iter_Count(&it2); - Test_AssertEqInt(count as int, 3); - - Print("All array+iter tests passed!"); - Array_Free(&arr); - return 0; -} -} diff --git a/apps/jwt-pitbul/src/Main.bux b/apps/jwt-pitbul/src/Main.bux index 2f4e0ac..8d6d0aa 100644 --- a/apps/jwt-pitbul/src/Main.bux +++ b/apps/jwt-pitbul/src/Main.bux @@ -91,11 +91,9 @@ func ParseAlg(name: String) -> JwtAlg { // Resolve key — for RSA/ECDSA, read PEM file; for HMAC/EdDSA, pass through // ============================================================================= func ResolveKey(alg: JwtAlg, keyArg: String) -> String { - let algTag: int = alg.tag; - // RSA and ECDSA: key is a path to PEM file - if algTag == JwtAlg_RS256 || algTag == JwtAlg_RS384 || algTag == JwtAlg_RS512 || - algTag == JwtAlg_ES256 || algTag == JwtAlg_ES384 { + if alg.tag == JwtAlg_RS256 || alg.tag == JwtAlg_RS384 || alg.tag == JwtAlg_RS512 || + alg.tag == JwtAlg_ES256 || alg.tag == JwtAlg_ES384 { if bux_file_exists(keyArg) != 0 { let pem: String = bux_read_file(keyArg); if pem as uint != 0 && String_Len(pem) > 0 { @@ -118,8 +116,7 @@ func ResolveKey(alg: JwtAlg, keyArg: String) -> String { // Check if algorithm is symmetric (HMAC) or asymmetric // ============================================================================= func IsSymmetric(alg: JwtAlg) -> bool { - let t: int = alg.tag; - return t == JwtAlg_HS256 || t == JwtAlg_HS384 || t == JwtAlg_HS512; + return alg.tag == JwtAlg_HS256 || alg.tag == JwtAlg_HS384 || alg.tag == JwtAlg_HS512; } // ============================================================================= @@ -210,13 +207,13 @@ func CmdDecode(token: String) -> int { // ============================================================================= func CmdKeygen(keyType: String) -> int { if String_Eq(keyType, "ed25519") { - let pub: *void = bux_alloc(32); + let pubBuf: *void = bux_alloc(32); let priv: *void = bux_alloc(32); - if !Ed25519_Keypair(pub, priv) { + if !Ed25519_Keypair(pubBuf, priv) { PrintLine("ERROR: Ed25519 key generation failed (OpenSSL 1.1.1+ required)"); return 1; } - let pubB64: String = bux_base64_encode(pub as String, 32); + let pubB64: String = bux_base64_encode(pubBuf as String, 32); let privB64: String = bux_base64_encode(priv as String, 32); PrintLine("Ed25519 keypair (base64):"); Print(" Public: "); diff --git a/bootstrap/hir_lower.nim b/bootstrap/hir_lower.nim index df01539..600411a 100644 --- a/bootstrap/hir_lower.nim +++ b/bootstrap/hir_lower.nim @@ -400,7 +400,14 @@ proc resolveExprType(ctx: var LowerCtx, expr: Expr): Type = else: return makeUnknown() of dkEnum: # Algebraic enum fields: tag and data - if expr.exprFieldName == "tag": + var hasData = false + for v in decl.declEnumVariants: + if v.fields.len > 0 or v.namedFields.len > 0: + hasData = true + break + if not hasData and expr.exprFieldName == "tag": + return makeNamed(objType.name) + elif expr.exprFieldName == "tag": return makeNamed(objType.name & "_Tag") elif expr.exprFieldName == "data": return makeNamed(objType.name & "_Data") @@ -670,6 +677,17 @@ proc lowerExpr(ctx: var LowerCtx, expr: Expr): HirNode = of ekField: let objType = ctx.resolveExprType(expr.exprFieldObj) let base = ctx.lowerExpr(expr.exprFieldObj) + # Simple enum .tag is the enum value itself + if objType.kind == tkNamed and expr.exprFieldName == "tag": + let sym = ctx.globalScope.lookup(objType.name) + if sym != nil and sym.decl != nil and sym.decl.kind == dkEnum: + var hasData = false + for v in sym.decl.declEnumVariants: + if v.fields.len > 0 or v.namedFields.len > 0: + hasData = true + break + if not hasData: + return base # Auto-dereference pointer types for field access if objType.isPointer: let arrowPtr = HirNode(kind: hArrowField, arrowFieldBase: base, @@ -703,9 +721,6 @@ proc lowerExpr(ctx: var LowerCtx, expr: Expr): HirNode = typ: makeVoid(), loc: loc) of ekStructInit: - var fields: seq[tuple[name: string, value: HirNode]] = @[] - for f in expr.exprStructInitFields: - fields.add((f.name, ctx.lowerExpr(f.value))) var structName = expr.exprStructInitName if expr.exprStructInitTypeArgs.len > 0: var suffix = "" @@ -714,6 +729,24 @@ proc lowerExpr(ctx: var LowerCtx, expr: Expr): HirNode = let argType = ctx.resolveTypeExpr(targ) suffix.add(argType.toString) structName = structName & "_" & suffix + # Simple enum init: EnumName { tag: EnumName_Variant } -> EnumName_Variant + var enumDecl: Decl = nil + let enumSym = ctx.globalScope.lookup(structName) + if enumSym != nil and enumSym.decl != nil and enumSym.decl.kind == dkEnum: + enumDecl = enumSym.decl + var isSimple = false + if enumDecl != nil: + for v in enumDecl.declEnumVariants: + if v.fields.len > 0 or v.namedFields.len > 0: + isSimple = true + break + isSimple = not isSimple + if isSimple and expr.exprStructInitFields.len == 1 and expr.exprStructInitFields[0].name == "tag": + let variantExpr = ctx.lowerExpr(expr.exprStructInitFields[0].value) + return variantExpr + var fields: seq[tuple[name: string, value: HirNode]] = @[] + for f in expr.exprStructInitFields: + fields.add((f.name, ctx.lowerExpr(f.value))) return HirNode(kind: hStructInit, structInitName: structName, structInitFields: fields, typ: typ, loc: loc) diff --git a/bootstrap/sema.nim b/bootstrap/sema.nim index 4415b12..eeba627 100644 --- a/bootstrap/sema.nim +++ b/bootstrap/sema.nim @@ -535,10 +535,17 @@ proc collectGlobals*(sema: var Sema) = if not sema.globalScope.define(sym): sema.emitError(decl.loc, &"duplicate symbol '{decl.declEnumName}'") sema.typeTable[decl.declEnumName] = t + # Check if algebraic or simple enum + var hasData = false + for variant in decl.declEnumVariants: + if variant.fields.len > 0 or variant.namedFields.len > 0: + hasData = true + break # For algebraic enums, add variant constants with _Tag type + # For simple enums, variant constants have the enum type itself for variant in decl.declEnumVariants: let variantName = decl.declEnumName & "_" & variant.name - let variantType = makeNamed(decl.declEnumName & "_Tag") + let variantType = if hasData: makeNamed(decl.declEnumName & "_Tag") else: makeNamed(decl.declEnumName) let variantSym = Symbol(kind: skConst, name: variantName, typ: variantType, decl: decl, isPublic: decl.isPublic) discard sema.globalScope.define(variantSym) @@ -563,24 +570,8 @@ proc collectGlobals*(sema: var Sema) = sema.emitError(decl.loc, &"duplicate symbol '{decl.declAliasName}'") sema.typeTable[decl.declAliasName] = t of dkUse: - # Imports: register imported names into scope - if decl.declUsePath.len > 0: - case decl.declUseKind - of ukMulti: - for name in decl.declUseNames: - if sema.globalScope.lookup(name) == nil: - let sym = Symbol(kind: skFunc, name: name, typ: makeUnknown(), isPublic: true) - discard sema.globalScope.define(sym) - of ukGlob: - let name = decl.declUsePath[^1] - if sema.globalScope.lookup(name) == nil: - let sym = Symbol(kind: skModule, name: name, typ: makeUnknown(), isPublic: true) - discard sema.globalScope.define(sym) - of ukSingle: - let name = decl.declUsePath[^1] - if sema.globalScope.lookup(name) == nil: - let sym = Symbol(kind: skFunc, name: name, typ: makeUnknown(), isPublic: true) - discard sema.globalScope.define(sym) + # Imports handled in second pass after all declarations are registered + discard of dkInterface: # Register interface for conformance checking sema.interfaceTable[decl.declInterfaceName] = decl @@ -641,6 +632,26 @@ proc collectGlobals*(sema: var Sema) = for decl in sema.module.items: if decl.kind == dkConst: discard sema.constFoldConstDecl(decl) + # Third pass: register imports after all real declarations are known + for decl in sema.module.items: + if decl.kind == dkUse: + if decl.declUsePath.len > 0: + case decl.declUseKind + of ukMulti: + for name in decl.declUseNames: + if sema.globalScope.lookup(name) == nil: + let sym = Symbol(kind: skFunc, name: name, typ: makeUnknown(), isPublic: true) + discard sema.globalScope.define(sym) + of ukGlob: + let name = decl.declUsePath[^1] + if sema.globalScope.lookup(name) == nil: + let sym = Symbol(kind: skModule, name: name, typ: makeUnknown(), isPublic: true) + discard sema.globalScope.define(sym) + of ukSingle: + let name = decl.declUsePath[^1] + if sema.globalScope.lookup(name) == nil: + let sym = Symbol(kind: skFunc, name: name, typ: makeUnknown(), isPublic: true) + discard sema.globalScope.define(sym) # --------------------------------------------------------------------------- # Expression type checking @@ -1085,7 +1096,14 @@ proc checkExpr(sema: var Sema, expr: Expr, scope: Scope): Type = sema.emitError(expr.loc, &"struct '{objType.name}' has no field '{expr.exprFieldName}'") elif sym.decl.kind == dkEnum: # Algebraic enum fields - if expr.exprFieldName == "tag": + var hasData = false + for v in sym.decl.declEnumVariants: + if v.fields.len > 0 or v.namedFields.len > 0: + hasData = true + break + if not hasData and expr.exprFieldName == "tag": + return makeNamed(objType.name) + elif expr.exprFieldName == "tag": return makeNamed(objType.name & "_Tag") elif expr.exprFieldName == "data": return makeNamed(objType.name & "_Data") diff --git a/lib/crypto/ecdsa.bux b/lib/crypto/ecdsa.bux index 8191604..1834019 100644 --- a/lib/crypto/ecdsa.bux +++ b/lib/crypto/ecdsa.bux @@ -6,30 +6,26 @@ module Std::Crypto::Ecdsa { import Std::Mem::{Alloc, Free}; import Std::String::{String_Len}; -extern func bux_ecdsa_sign_p256(pemKey: String, keylen: int, data: String, datalen: int, siglen: *int) -> String; -extern func bux_ecdsa_sign_p384(pemKey: String, keylen: int, data: String, datalen: int, siglen: *int) -> String; -extern func bux_ecdsa_verify_p256(pemKey: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int; -extern func bux_ecdsa_verify_p384(pemKey: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int; +// Extern declarations for the runtime C implementations +extern func bux_ecdsa_sign_p256(key: String, keylen: int, data: String, datalen: int, outlen: *int) -> String; +extern func bux_ecdsa_verify_p256(key: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int; +extern func bux_ecdsa_sign_p384(key: String, keylen: int, data: String, datalen: int, outlen: *int) -> String; +extern func bux_ecdsa_verify_p384(key: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int; extern func bux_base64_encode(data: String, len: int) -> String; extern func bux_base64_decode(data: String, len: int, outlen: *int) -> String; -// --- ECDSA P-256 (ES256) --- - func Ecdsa_SignP256(pemPrivateKey: String, data: String) -> String { let siglen: int = 0; - return bux_ecdsa_sign_p256(pemPrivateKey, String_Len(pemPrivateKey) as int, - data, String_Len(data) as int, &siglen); + return bux_ecdsa_sign_p256(pemPrivateKey, String_Len(pemPrivateKey) as int, data, String_Len(data) as int, &siglen); } func Ecdsa_SignP256Base64(pemPrivateKey: String, data: String) -> String { - let sig: String = Ecdsa_SignP256(pemPrivateKey, data); - return bux_base64_encode(sig, String_Len(sig) as int); + let raw: String = Ecdsa_SignP256(pemPrivateKey, data); + return bux_base64_encode(raw, String_Len(raw) as int); } func Ecdsa_VerifyP256(pemPublicKey: String, data: String, signature: String) -> bool { - let r: int = bux_ecdsa_verify_p256(pemPublicKey, String_Len(pemPublicKey) as int, - data, String_Len(data) as int, - signature, String_Len(signature) as int); + let r: int = bux_ecdsa_verify_p256(pemPublicKey, String_Len(pemPublicKey) as int, data, String_Len(data) as int, signature, String_Len(signature) as int); return r == 1; } @@ -39,23 +35,18 @@ func Ecdsa_VerifyP256Base64(pemPublicKey: String, data: String, signatureB64: St return Ecdsa_VerifyP256(pemPublicKey, data, sig); } -// --- ECDSA P-384 (ES384) --- - func Ecdsa_SignP384(pemPrivateKey: String, data: String) -> String { let siglen: int = 0; - return bux_ecdsa_sign_p384(pemPrivateKey, String_Len(pemPrivateKey) as int, - data, String_Len(data) as int, &siglen); + return bux_ecdsa_sign_p384(pemPrivateKey, String_Len(pemPrivateKey) as int, data, String_Len(data) as int, &siglen); } func Ecdsa_SignP384Base64(pemPrivateKey: String, data: String) -> String { - let sig: String = Ecdsa_SignP384(pemPrivateKey, data); - return bux_base64_encode(sig, String_Len(sig) as int); + let raw: String = Ecdsa_SignP384(pemPrivateKey, data); + return bux_base64_encode(raw, String_Len(raw) as int); } func Ecdsa_VerifyP384(pemPublicKey: String, data: String, signature: String) -> bool { - let r: int = bux_ecdsa_verify_p384(pemPublicKey, String_Len(pemPublicKey) as int, - data, String_Len(data) as int, - signature, String_Len(signature) as int); + let r: int = bux_ecdsa_verify_p384(pemPublicKey, String_Len(pemPublicKey) as int, data, String_Len(data) as int, signature, String_Len(signature) as int); return r == 1; } diff --git a/lib/crypto/ed25519.bux b/lib/crypto/ed25519.bux index d0bab8b..8e8eba5 100644 --- a/lib/crypto/ed25519.bux +++ b/lib/crypto/ed25519.bux @@ -27,17 +27,17 @@ func Ed25519_Keypair(pubKey: *void, privKey: *void) -> bool { // Convenience: generate and return base64-encoded keypair func Ed25519_KeypairBase64() -> String { - let pub: *void = Alloc(ED25519_PUBKEY_SIZE as uint); + let pubBuf: *void = Alloc(ED25519_PUBKEY_SIZE as uint); let priv: *void = Alloc(ED25519_PRIVKEY_SIZE as uint); - if bux_ed25519_keypair(pub, priv) != 1 { - Free(pub); + if bux_ed25519_keypair(pubBuf, priv) != 1 { + Free(pubBuf); Free(priv); return ""; } // Return "pub_b64:priv_b64" - let pubB64: String = bux_base64_encode(pub as String, ED25519_PUBKEY_SIZE); + let pubB64: String = bux_base64_encode(pubBuf as String, ED25519_PUBKEY_SIZE); let privB64: String = bux_base64_encode(priv as String, ED25519_PRIVKEY_SIZE); - Free(pub); + Free(pubBuf); Free(priv); let pair: String = String_Concat(pubB64, ":"); return String_Concat(pair, privB64); diff --git a/lib/crypto/rsa.bux b/lib/crypto/rsa.bux index 24af15d..b177cfd 100644 --- a/lib/crypto/rsa.bux +++ b/lib/crypto/rsa.bux @@ -6,12 +6,13 @@ module Std::Crypto::Rsa { import Std::Mem::{Alloc, Free}; import Std::String::{String_Len}; -extern func bux_rsa_sign_sha256(pemKey: String, keylen: int, data: String, datalen: int, siglen: *int) -> String; -extern func bux_rsa_sign_sha384(pemKey: String, keylen: int, data: String, datalen: int, siglen: *int) -> String; -extern func bux_rsa_sign_sha512(pemKey: String, keylen: int, data: String, datalen: int, siglen: *int) -> String; -extern func bux_rsa_verify_sha256(pemKey: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int; -extern func bux_rsa_verify_sha384(pemKey: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int; -extern func bux_rsa_verify_sha512(pemKey: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int; +// Extern declarations for the runtime C implementations +extern func bux_rsa_sign_sha256(key: String, keylen: int, data: String, datalen: int, outlen: *int) -> String; +extern func bux_rsa_sign_sha384(key: String, keylen: int, data: String, datalen: int, outlen: *int) -> String; +extern func bux_rsa_sign_sha512(key: String, keylen: int, data: String, datalen: int, outlen: *int) -> String; +extern func bux_rsa_verify_sha256(key: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int; +extern func bux_rsa_verify_sha384(key: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int; +extern func bux_rsa_verify_sha512(key: String, keylen: int, data: String, datalen: int, sig: String, siglen: int) -> int; extern func bux_base64_encode(data: String, len: int) -> String; extern func bux_base64_decode(data: String, len: int, outlen: *int) -> String; @@ -20,36 +21,33 @@ extern func bux_base64_decode(data: String, len: int, outlen: *int) -> String; // Rsa_SignSha256: sign data with RSA private key (PEM format), returns raw signature func Rsa_SignSha256(pemPrivateKey: String, data: String) -> String { let siglen: int = 0; - return bux_rsa_sign_sha256(pemPrivateKey, String_Len(pemPrivateKey) as int, - data, String_Len(data) as int, &siglen); + return bux_rsa_sign_sha256(pemPrivateKey, String_Len(pemPrivateKey) as int, data, String_Len(data) as int, &siglen); } func Rsa_SignSha384(pemPrivateKey: String, data: String) -> String { let siglen: int = 0; - return bux_rsa_sign_sha384(pemPrivateKey, String_Len(pemPrivateKey) as int, - data, String_Len(data) as int, &siglen); + return bux_rsa_sign_sha384(pemPrivateKey, String_Len(pemPrivateKey) as int, data, String_Len(data) as int, &siglen); } func Rsa_SignSha512(pemPrivateKey: String, data: String) -> String { let siglen: int = 0; - return bux_rsa_sign_sha512(pemPrivateKey, String_Len(pemPrivateKey) as int, - data, String_Len(data) as int, &siglen); + return bux_rsa_sign_sha512(pemPrivateKey, String_Len(pemPrivateKey) as int, data, String_Len(data) as int, &siglen); } // Convenience: sign and return base64-encoded signature func Rsa_SignSha256Base64(pemPrivateKey: String, data: String) -> String { - let sig: String = Rsa_SignSha256(pemPrivateKey, data); - return bux_base64_encode(sig, String_Len(sig) as int); + let raw: String = Rsa_SignSha256(pemPrivateKey, data); + return bux_base64_encode(raw, String_Len(raw) as int); } func Rsa_SignSha384Base64(pemPrivateKey: String, data: String) -> String { - let sig: String = Rsa_SignSha384(pemPrivateKey, data); - return bux_base64_encode(sig, String_Len(sig) as int); + let raw: String = Rsa_SignSha384(pemPrivateKey, data); + return bux_base64_encode(raw, String_Len(raw) as int); } func Rsa_SignSha512Base64(pemPrivateKey: String, data: String) -> String { - let sig: String = Rsa_SignSha512(pemPrivateKey, data); - return bux_base64_encode(sig, String_Len(sig) as int); + let raw: String = Rsa_SignSha512(pemPrivateKey, data); + return bux_base64_encode(raw, String_Len(raw) as int); } // --- RSA Verify --- @@ -57,23 +55,17 @@ func Rsa_SignSha512Base64(pemPrivateKey: String, data: String) -> String { // Rsa_VerifySha256: verify raw signature against data with RSA public key (PEM) // Returns true if signature is valid. func Rsa_VerifySha256(pemPublicKey: String, data: String, signature: String) -> bool { - let r: int = bux_rsa_verify_sha256(pemPublicKey, String_Len(pemPublicKey) as int, - data, String_Len(data) as int, - signature, String_Len(signature) as int); + let r: int = bux_rsa_verify_sha256(pemPublicKey, String_Len(pemPublicKey) as int, data, String_Len(data) as int, signature, String_Len(signature) as int); return r == 1; } func Rsa_VerifySha384(pemPublicKey: String, data: String, signature: String) -> bool { - let r: int = bux_rsa_verify_sha384(pemPublicKey, String_Len(pemPublicKey) as int, - data, String_Len(data) as int, - signature, String_Len(signature) as int); + let r: int = bux_rsa_verify_sha384(pemPublicKey, String_Len(pemPublicKey) as int, data, String_Len(data) as int, signature, String_Len(signature) as int); return r == 1; } func Rsa_VerifySha512(pemPublicKey: String, data: String, signature: String) -> bool { - let r: int = bux_rsa_verify_sha512(pemPublicKey, String_Len(pemPublicKey) as int, - data, String_Len(data) as int, - signature, String_Len(signature) as int); + let r: int = bux_rsa_verify_sha512(pemPublicKey, String_Len(pemPublicKey) as int, data, String_Len(data) as int, signature, String_Len(signature) as int); return r == 1; }