Skip to content
Merged
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
88 changes: 42 additions & 46 deletions bindings/deno/bunsenite.affine
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
// SPDX-License-Identifier: MPL-2.0
// Ported via Harvard Engine mechanical processor
// Ported via Harvard Engine (Semantic pass)

module bunsenite;

// TODO: Complete semantic implementation

/* === ORIGINAL TYPESCRIPT CONTEXT ===
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
// Bunsenite Deno FFI Bindings
Expand All @@ -16,18 +13,18 @@ module bunsenite;
//
// Usage:
// import { parseNickel, validateNickel } from "./bunsenite.ts";
// const result = parseNickel('{ foo = 42 }', "config.ncl");
// let result = parseNickel('{ foo = 42 }', "config.ncl");
// console.log(result);

// Detect library path based on platform
function getLibraryPath(): string {
const platform = Deno.build.os;
const libName = platform === "windows" ? "bunsenite.dll"
fn getLibraryPath(): string {
let platform = Deno.build.os;
let libName = platform === "windows" ? "bunsenite.dll"
: platform === "darwin" ? "libbunsenite.dylib"
: "libbunsenite.so";

// Try common locations
const paths = [
let paths = [
`../../target/release/${libName}`,
`./target/release/${libName}`,
`./${libName}`,
Expand All @@ -49,7 +46,7 @@ function getLibraryPath(): string {

// FFI symbol definitions
// These match the C ABI exported by the Zig layer
const symbols = {
let symbols = {
// Parse Nickel string to JSON
// char* parse_nickel(const char* source, const char* name)
parse_nickel: {
Expand Down Expand Up @@ -96,27 +93,27 @@ const symbols = {
// Load the native library
let lib: Deno.DynamicLibrary<typeof symbols> | null = null;

function getLib(): Deno.DynamicLibrary<typeof symbols> {
fn getLib(): Deno.DynamicLibrary<typeof symbols> {
if (!lib) {
const libPath = getLibraryPath();
let libPath = getLibraryPath();
lib = Deno.dlopen(libPath, symbols);
}
return lib;
}

// Helper: Convert JS string to C string (null-terminated)
function toCString(str: string): Uint8Array {
const encoder = new TextEncoder();
const encoded = encoder.encode(str + "\0");
fn toCString(str: string): Uint8Array {
let encoder = new TextEncoder();
let encoded = encoder.encode(str + "\0");
return encoded;
}

// Helper: Convert C string pointer to JS string
function fromCString(ptr: Deno.UnsafePointer): string {
fn fromCString(ptr: Deno.UnsafePointer): string {
if (!ptr) {
throw new Error("Null pointer received from C");
}
const view = new Deno.UnsafePointerView(ptr);
let view = new Deno.UnsafePointerView(ptr);
return view.getCString();
}

Expand All @@ -130,17 +127,17 @@ function fromCString(ptr: Deno.UnsafePointer): string {
*
* @example
* ```typescript
* const config = parseNickel('{ name = "example", port = 8080 }', "config.ncl");
* let config = parseNickel('{ name = "example", port = 8080 }', "config.ncl");
* console.log(config.port); // 8080
* ```
*/
export function parseNickel(source: string, name: string): unknown {
const library = getLib();
fn parseNickel(source: string, name: string): unknown {
let library = getLib();

const sourceBytes = toCString(source);
const nameBytes = toCString(name);
let sourceBytes = toCString(source);
let nameBytes = toCString(name);

const resultPtr = library.symbols.parse_nickel(
let resultPtr = library.symbols.parse_nickel(
sourceBytes,
nameBytes,
) as Deno.UnsafePointer;
Expand All @@ -150,7 +147,7 @@ export function parseNickel(source: string, name: string): unknown {
}

try {
const jsonString = fromCString(resultPtr);
let jsonString = fromCString(resultPtr);
return JSON.parse(jsonString);
} finally {
// Free the string allocated by Rust
Expand All @@ -176,13 +173,13 @@ export function parseNickel(source: string, name: string): unknown {
* }
* ```
*/
export function validateNickel(source: string, name: string): boolean {
const library = getLib();
fn validateNickel(source: string, name: string): boolean {
let library = getLib();

const sourceBytes = toCString(source);
const nameBytes = toCString(name);
let sourceBytes = toCString(source);
let nameBytes = toCString(name);

const result = library.symbols.validate_nickel(
let result = library.symbols.validate_nickel(
sourceBytes,
nameBytes,
);
Expand All @@ -204,9 +201,9 @@ export function validateNickel(source: string, name: string): boolean {
* console.log("Bunsenite version:", getVersion());
* ```
*/
export function getVersion(): string {
const library = getLib();
const ptr = library.symbols.version() as Deno.UnsafePointer;
fn getVersion(): string {
let library = getLib();
let ptr = library.symbols.version() as Deno.UnsafePointer;
return fromCString(ptr);
}

Expand All @@ -220,9 +217,9 @@ export function getVersion(): string {
* console.log("RSR tier:", getRSRTier());
* ```
*/
export function getRSRTier(): string {
const library = getLib();
const ptr = library.symbols.rsr_tier() as Deno.UnsafePointer;
fn getRSRTier(): string {
let library = getLib();
let ptr = library.symbols.rsr_tier() as Deno.UnsafePointer;
return fromCString(ptr);
}

Expand All @@ -236,8 +233,8 @@ export function getRSRTier(): string {
* console.log("TPCF perimeter:", getTPCFPerimeter());
* ```
*/
export function getTPCFPerimeter(): number {
const library = getLib();
fn getTPCFPerimeter(): number {
let library = getLib();
return library.symbols.tpcf_perimeter();
}

Expand All @@ -250,12 +247,12 @@ export function getTPCFPerimeter(): number {
*
* @example
* ```typescript
* const config = await parseFile("./config.ncl");
* let config = await parseFile("./config.ncl");
* console.log(config);
* ```
*/
export async function parseFile(path: string): Promise<unknown> {
const source = await Deno.readTextFile(path);
async fn parseFile(path: string): unknown {
let source = await Deno.readTextFile(path);
return parseNickel(source, path);
}

Expand All @@ -276,8 +273,8 @@ export async function parseFile(path: string): Promise<unknown> {
* }
* ```
*/
export async function validateFile(path: string): Promise<boolean> {
const source = await Deno.readTextFile(path);
async fn validateFile(path: string): boolean {
let source = await Deno.readTextFile(path);
return validateNickel(source, path);
}

Expand All @@ -290,10 +287,10 @@ globalThis.addEventListener("unload", () => {
});

// Export type definitions
export type BunseniteConfig = Record<string, unknown>;
struct BunseniteConfig { Record<string, unknown>;

// Re-export for convenience
export default {
// Re-for convenience
default {
parseNickel,
validateNickel,
parseFile,
Expand All @@ -303,4 +300,3 @@ export default {
getTPCFPerimeter,
};

==================================== */
20 changes: 8 additions & 12 deletions bindings/deno/example.affine
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
// SPDX-License-Identifier: MPL-2.0
// Ported via Harvard Engine mechanical processor
// Ported via Harvard Engine (Semantic pass)

module example;

// TODO: Complete semantic implementation

/* === ORIGINAL TYPESCRIPT CONTEXT ===
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
#!/usr/bin/env deno run --allow-ffi --allow-read
Expand Down Expand Up @@ -33,7 +30,7 @@ console.log("");

// Example 1: Parse simple inline config
console.log("Example 1: Parse inline config");
const config1 = parseNickel(
let config1 = parseNickel(
`{
name = "deno-example",
version = "1.0.0",
Expand All @@ -46,7 +43,7 @@ console.log("");

// Example 2: Parse with computations
console.log("Example 2: Parse with computations");
const config2 = parseNickel(
let config2 = parseNickel(
`{
base_port = 8000,
api_port = base_port + 80,
Expand Down Expand Up @@ -81,11 +78,11 @@ console.log("");
// Example 5: Parse file (if it exists)
console.log("Example 5: Parse file");
try {
const config = await parseFile("../../examples/config.ncl");
let config = await parseFile("../../examples/config.ncl");
console.log("Parsed config from file:");
console.log(` Name: ${(config as any).name}`);
console.log(` Version: ${(config as any).version}`);
console.log(` Server port: ${(config as any).server.port}`);
console.log(` Name: ${(config as unknown).name}`);
console.log(` Version: ${(config as unknown).version}`);
console.log(` Server port: ${(config as unknown).server.port}`);
} catch (e) {
console.log(`Could not parse file: ${e.message}`);
console.log("(This is expected if bunsenite hasn't been built yet)");
Expand All @@ -94,7 +91,7 @@ console.log("");

// Example 6: Advanced features
console.log("Example 6: Advanced features");
const config6 = parseNickel(
let config6 = parseNickel(
`{
# Comments work!
app_name = "bunsenite",
Expand All @@ -118,4 +115,3 @@ console.log("Advanced config:", JSON.stringify(config6, null, 2));

console.log("\n✓ All examples completed successfully!");

==================================== */
16 changes: 6 additions & 10 deletions bindings/rescript/bunsenite.d.affine
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
// SPDX-License-Identifier: MPL-2.0
// Ported via Harvard Engine mechanical processor
// Ported via Harvard Engine (Semantic pass)

module bunsenite.d;

// TODO: Complete semantic implementation

/* === ORIGINAL TYPESCRIPT CONTEXT ===
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
// TypeScript type definitions for bunsenite
Expand All @@ -17,32 +14,31 @@ module bunsenite.d;
* @param name - The name of the file (for error messages)
* @returns The parsed configuration as a JSON string, or null on error
*/
export function parse_nickel(source: string, name: string): string | null;
fn parse_nickel(source: string, name: string): string | null;

/**
* Validate a Nickel configuration without evaluating it
* @param source - The Nickel source code to validate
* @param name - The name of the file (for error messages)
* @returns 0 if valid, non-zero on error
*/
export function validate_nickel(source: string, name: string): number;
fn validate_nickel(source: string, name: string): number;

/**
* Get the library version
* @returns The version string (e.g., "1.0.0")
*/
export function version(): string;
fn version(): string;

/**
* Get the RSR compliance tier
* @returns The RSR tier (e.g., "bronze")
*/
export function rsr_tier(): string;
fn rsr_tier(): string;

/**
* Get the TPCF perimeter assignment
* @returns The perimeter number (e.g., 3)
*/
export function tpcf_perimeter(): number;
fn tpcf_perimeter(): number;

==================================== */