[go: up one dir, main page]

Skip to content

Programming language with a tree-walking interpreter written in Rust©™.

License

Notifications You must be signed in to change notification settings

franeklubi/luxya

Repository files navigation

luxya ✨

Luxya is a Lox-based programming language with a tree-walking interpreter written in Rust©™.

luxya logo

To download precompiled binaries for GNU/Linux and Windows visit the releases page!



Lox-luxya differences

Syntax differences:

  • function declarations are expressions, rather than statements, so you can create anonymous (but not strictly) functions you want to use in-place: function_name(10, a, fun () { print "callback" })
  • introduced let instead of var, and const for immutable declarations
  • if's, else's, and for's body has to be a block
  • ifs condition doesn't need to be a grouping (basically you can do: if true { ... })
  • although there is no type coercion, any value that's not strictly true will be treated as not true when placed in if's or for's condition
  • for's initialization consists of three, not grouped fields (e.g.: for let i = 0; i < 10; i = i + 1 { ... })
  • there are no while loops, but you can achieve the same behaviour with for (while true { ... } is the same as for ; true; { ... })
  • you can state an infinite loop by omitting every field: for ;; {}
  • init (Lox's constructor method) is named constructor
  • you cannot call an instance's constructor directly (constructors are only callable by using Classname() or super())
  • to call a superclass's constructor you need to call the super keyword, as you would a function
  • inheritance is done with the extends keyword, replacing the < syntax
  • chars, which you can read more about here

Backend differences:

  • numbers are IEEE 754-2008 compliant (rust's f64 underneath)
  • no type coercion, no truthy nor falsy values
  • no visitor pattern
  • reference counting because there's no garbage collector to leverage
  • shadowing of named values is permitted

Native functions:

You can find full list of native functions here

Usage

To run any script source run:

$ luxya <source>

To run in REPL mode (which is not yet finished):

$ luxya

Examples

for let i = 0; i < 10; i = i + 1 {
	print i;
}
fun shout(text) {
	print text + "!";
}

shout("hi");
class Language {
	constructor(name) {
		this.name = name;
	}

	say_language() {
		print this.name;
	}
}

class Luxya extends Language {
	constructor() {
		super("luxya");
	}

	say_language() {
		print "✨✨✨";
		super.say_language();
		print "✨✨✨";
	}
}

const luxya = Luxya();

luxya.say_language();

Compilation and development

The source comprises two parts:

  • the src/ast/* generated by tools/generate_ast.py
  • the rest

To get a release build you can use just:

$ just

Or use cargo:

$ cargo build --release --verbose

There are also a couple of useful dev commands like:

# run REPL in watch mode
$ just watch

# run the `sample_program.lux` in watch mode
# (script source overridable with sample_program_path in justfile)
$ just watch_sample

# run the `generate_ast.py` script with mypy checks in watch mode
# (script source overridable with generate_ast_path in justfile)
$ just watch_generate_ast