Status: approved version 1 baseline. Changes to visible syntax or semantics
require a recorded decision. Nova128 is the approved project name.
Nova128 is a small, predictable, statically typed object-oriented language that can be compiled on a Commodore 128 with bounded memory.
Version 1 prioritizes:
Compactness is a product constraint. A feature is not part of version 1 unless this specification defines its syntax, semantics, diagnostics, and tests.
$0D).$41-$5A and
$C1-$DA; the lexer normalizes them for comparison..n8, .err,
and .map names fit the Commodore DOS filename limit._.// begins a comment that continues through the end of the logical line.$ introduces hexadecimal and % introduces
binary.\",
\\, \n, and \r.\', \\, \n, or \r.(, ), [, ], ,, ., :, =, +, -,
*, /, <, >, <>, <=, >=, and the single quote that delimits
character literals. (<= and >= were missing from this list although
section 8 defines them; corrected in E02-S02.)\n and \r both produce PETSCII $0D, the Commodore line end (D119,
proposed).and, or, and not; && and || are
not aliases.| 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.
null.null.type[length].byte widens implicitly to word or integer.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.null is assignable to any class or interface reference.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.
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.
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.
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.
private.public.self reference.as type.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.init.delete expression invokes destroy when present and then releases storage.null is a no-op.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.
From highest to lowest precedence:
not and unary -* and /+ and -<, <=, >, and >==, <>andorArithmetic 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.
self.field selects the field.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.
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:
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
Powered by TurnKey Linux.