Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

13KB


type: language-specification source-path: approved feature requests and expert design plan ingested-at: 2026-11-07 version: 0.1-draft

Nova128 Language Specification

Status: approved version 1 baseline. Changes to visible syntax or semantics require a recorded decision. Nova128 is the approved project name.

1. Design Goals

Nova128 is a small, predictable, statically typed object-oriented language that can be compiled on a Commodore 128 with bounded memory.

Version 1 prioritizes:

  • understandable generated 8502 code;
  • deterministic memory and execution costs;
  • useful encapsulation and interface polymorphism;
  • source that is comfortable to enter on a Commodore keyboard;
  • diagnostics that remain readable on a 40-column display;
  • a compiler architecture that fits within the C128's banked memory.

Compactness is a product constraint. A feature is not part of version 1 unless this specification defines its syntax, semantics, diagnostics, and tests.

2. Source Profile

2.1 Physical format

  • Source files are PETSCII sequential files.
  • Logical lines end in carriage return ($0D).
  • The compiler accepts a missing final carriage return.
  • A source file may contain both PETSCII letter ranges $41-$5A and $C1-$DA; the lexer normalizes them for comparison.
  • The version 1 editor profile permits at most 80 bytes per logical line, 18,999 source bytes, and 599 logical lines.
  • A source base name should contain at most 12 characters so .n8, .err, and .map names fit the Commodore DOS filename limit.
  • One source file produces one program in version 1.

2.2 Lexical rules

  • Keywords and identifiers are case-insensitive.
  • Diagnostics and map files preserve the spelling of the first declaration.
  • Identifiers begin with a letter and continue with letters, digits, or _.
  • At most 16 identifier characters are significant. Longer identifiers are an error rather than being silently truncated.
  • Spaces and tabs separate tokens.
  • A newline terminates a statement or declaration. Version 1 does not continue expressions across lines and does not allow multiple statements on one line.
  • // begins a comment that continues through the end of the logical line.
  • Decimal numbers use digits. $ introduces hexadecimal and % introduces binary.
  • String literals use double quotes. Version 1 escape sequences are \", \\, \n, and \r.
  • Character literals use single quotes and contain exactly one PETSCII character or one supported escape: \', \\, \n, or \r.
  • Reserved punctuation is (, ), [, ], ,, ., :, =, +, -, *, /, <, >, <>, and the single quote that delimits character literals.
  • Boolean operators are the words and, or, and not; && and || are not aliases.

3. Types and Values

3.1 Primitive types

Type Size Values
boolean 1 byte false (0) or true (1)
byte 1 byte 0 through 255
char 1 byte One PETSCII byte
integer 2 bytes Signed two's-complement -32768 through 32767
word 2 bytes Unsigned 0 through 65535

String literals are length-address pairs in generated read-only data. General mutable string variables are deferred. print accepts a string literal or a supported scalar value.

3.2 Reference types

  • Each class name defines a concrete object-reference type.
  • Each interface name defines an interface-reference type.
  • A concrete object reference is logically an address or null.
  • An interface reference identifies both an object and its implementation of a particular interface, or is null.
  • Reference assignment copies identity; it does not copy object fields.
  • Equality and inequality compare object identity.

3.3 Arrays

  • Version 1 supports fixed-size arrays with a compile-time positive length, written as type[length].
  • Arrays may be fields or local variables.
  • Array indexing is zero-based.
  • Bounds checking is controlled by the compiler's debug/release option.
  • Arrays of interface values use the interface representation defined by the ABI; language code does not observe its byte layout.

3.4 Conversions

  • byte widens implicitly to word or integer.
  • A character literal has type char. char does not silently become text or a number in version 1.
  • boolean never converts to or from a numeric type implicitly.
  • word and integer do not convert implicitly in either direction.
  • A class reference converts implicitly to an interface reference only when the class implements that interface.
  • An interface reference never converts implicitly to a concrete class.
  • null is assignable to any class or interface reference.

4. Program Structure

A file contains zero or more interface declarations, zero or more class declarations, and exactly one program declaration. Declarations may refer to types declared later in the file.

Simplified grammar uses {x} for repetition and [x] for an optional part:

file          = { interface-decl | class-decl }, program-decl, EOF ;

interface-decl = "interface", identifier, EOL,
                 { method-signature },
                 "end", "interface", EOL ;

class-decl     = "class", identifier,
                 [ "implements", type-list ], EOL,
                 { field-decl | method-decl },
                 "end", "class", EOL ;

program-decl   = "program", identifier, EOL,
                 { variable-decl | statement },
                 "end", "program", EOL ;

method-signature = "method", identifier, "(", [ parameter-list ], ")",
                   [ "as", type ], EOL ;

method-decl    = [ access ], "method", identifier, "(",
                 [ parameter-list ], ")", [ "as", type ], EOL,
                 { variable-decl }, { statement },
                 "end", "method", EOL ;

field-decl     = [ access ], type, identifier, EOL ;
variable-decl  = "var", identifier, "as", type, EOL ;
access         = "public" | "private" ;
type-list      = identifier, { ",", identifier } ;

The complete parser may use equivalent productions, but accepted and rejected programs must follow the behavior in this specification.

5. Interfaces

5.1 Declaration

An interface contains method signatures only:

interface Printable
  method print()
end interface

Interfaces cannot declare fields, constructors, destructors, method bodies, or access modifiers. Interface inheritance and default methods are deferred.

5.2 Implementation

A class implements one or more interfaces with a comma-separated list:

class Counter implements Printable, Resettable

For every interface method, the class must provide exactly one public method with the same case-insensitive name, parameter count, parameter types, and return type. Version 1 has no method overloading, so a class cannot declare two methods with the same name.

If two implemented interfaces require the same signature, one class method may satisfy both. If they use the same name with incompatible signatures, the class declaration is an error.

5.3 Interface calls

Calls made through a concrete class type are statically bound. Calls made through an interface type are dynamically dispatched to the object's class implementation.

var output as Printable
output = new Counter(10)
output.print()

Calling a method on a null interface reference is a runtime fault in debug mode. Release behavior must still terminate through the defined runtime-error path rather than jumping through address zero.

6. Classes and Objects

6.1 Fields and access

  • Fields default to private.
  • Methods default to public.
  • Private members are accessible only inside methods of their declaring class.
  • Version 1 has no class inheritance, protected access, static fields, or static methods.

6.2 Methods

  • An instance method has an implicit self reference.
  • Parameters are passed by value. Passing a reference copies the reference.
  • Local variables must be declared before executable statements in a method.
  • A non-returning method omits as type.
  • A returning method must return a compatible value on every reachable path.
  • Recursion is permitted by the language but bounded by the generated program's hardware and software stacks.

6.3 Construction and destruction

  • init is the optional constructor name. A class may declare at most one.
  • destroy is the optional destructor name. It takes no explicit parameters and returns no value.
  • new Class(args) allocates zero-initialized storage and then invokes init.
  • If allocation fails, the runtime follows the defined out-of-memory path and does not call init.
  • delete expression invokes destroy when present and then releases storage.
  • Deleting null is a no-op.
  • Deleting through an interface reference acts on the underlying object.
  • Using a reference after deletion is erroneous; version 1 does not attempt complete alias or lifetime proof.

7. Statements

Version 1 statements are:

assignment    target = expression
call          expression.method(arguments)
if            if expression
                statements
              [else
                statements]
              end if
while         while expression
                statements
              end while
for           for name = expression to expression [step expression]
                statements
              end for
return        return [expression]
print         print expression
delete        delete expression

Conditions must have type boolean; numeric values are not truth values. and and or short-circuit from left to right. A for loop evaluates its end and step expressions once before the first iteration.

8. Expressions

From highest to lowest precedence:

  1. Parentheses, member access, calls, and indexing
  2. Unary not and unary -
  3. * and /
  4. + and -
  5. <, <=, >, and >=
  6. =, <>
  7. and
  8. or

Arithmetic is performed in the operand type after permitted widening. Version 1 arithmetic overflow always wraps in the destination's two's-complement or unsigned representation. Debug and release builds have identical overflow semantics. Division by zero follows the runtime-error path.

9. Names and Scopes

  • Top-level interface and class names share one type namespace.
  • Field and method names occupy separate namespaces within a class.
  • Parameters and locals share a method-local namespace.
  • A local or parameter may shadow a field; self.field selects the field.
  • Duplicate declarations in the same namespace are errors.
  • Forward references to top-level types and methods are permitted because the compiler's declaration pass records signatures before bodies are compiled.

10. Built-in Operations

Version 1 reserves these operations:

  • print value — output a string literal, char, byte, word, integer, or boolean through the runtime's KERNAL-compatible text layer.
  • new Class(args) — allocate and construct an object.
  • delete reference — destroy and release an object.

Additional machine and KERNAL facilities will be introduced through explicit runtime APIs rather than unrestricted inline assembly in version 1.

11. Diagnostics

Diagnostics have stable codes and source positions. The screen form must fit a 40-column display:

E014 TEST.N8 23 7
BYTE EXPECTED; WORD FOUND

The compiler writes the complete diagnostic list to TEST.ERR. It stops after 20 errors by default so a malformed file cannot exhaust compiler memory.

Required diagnostic categories include:

  • invalid PETSCII or malformed token;
  • line, file, or identifier limit exceeded;
  • duplicate or unknown name;
  • syntax error with expected token;
  • type mismatch or illegal conversion;
  • access violation;
  • incomplete or conflicting interface implementation;
  • missing return;
  • resource limit, disk error, or output collision.

12. Complete Example

interface Printable
  method print()
end interface

interface Resettable
  method reset()
end interface

class Counter implements Printable, Resettable
  private word value

  public method init(start as word)
    self.value = start
  end method

  public method increment()
    self.value = self.value + 1
  end method

  public method print()
    print self.value
  end method

  public method reset()
    self.value = 0
  end method
end class

program Main
  var count as Counter
  var output as Printable

  count = new Counter(10)
  count.increment()
  output = count
  output.print()
  delete output
end program

Open Questions

  • Which additional KERNAL-backed library operations belong in the first standard runtime after the compiler core is proven.
  • Which runtime-fault messages fit after the generated-program memory map is measured; stable fault codes and a map-resolvable address are required.

Powered by TurnKey Linux.