~otheb/stf

9aa402e3db06fe34c180363426570273dec16d96 — Olie Ayre 3 years ago 7523a9a master
Update readme

Note: for some reason `dub run` and `dub build` throw linker errors,
however compiling with dmd does not. Please run with
`dmd -of=stf **.d && ./stf` in the mean time.
3 files changed, 69 insertions(+), 60 deletions(-)

M README
M design
M lexer.d
M README => README +57 -55
@@ 1,57 1,59 @@
                                  ### STF ###

STF is - for now - a toy language vaguely resembling Forth. One goal of it is to
stay as simple as possible, using only a single stack, and featuring static
typing. It is interpreted for now, but may later be able to compile down to
binary.

	# SYNTAX

Syntax is largely what you'd expect from a Forth dialect. Source code is
comprised of a list of items, each of which can be either a value literal or a
keyword. A value literal is simply pushed to the stack. A keyword can have a
huge variety of effects, but vaguely falls into 3 categories:

* Built-ins, which may behave as functions, flow control, or scope-management
  among other things.
* Functions, which call off to user- or library-defined subroutines.
* Variables, which reference values further down the stack.

	# BUILT-INS

. ( * -- )
	Dumps the top of the stack to the terminal.
.s ( *... -- )
	Dumps the entire stack to the terminal.
pr ( * -- )
	Prints the top of the stack without a newline.
rd ( -- string )
	Reads a string to the terminal from stdin.
+ ( int int -- int ) ( int float -- float ) ( float int -- float )
  ( float float -- float )
	Pops 2 numbers and pushes their sum.
- ( int int -- int ) ( int float -- float ) ( float int -- float )
  ( float float -- float )
	Pops 2 numbers and pushes their difference.
* ( int int -- int ) ( int float -- float ) ( float int -- float )
  ( float float -- float )
	Pops 2 numbers and pushes their product.
/ ( int int -- int ) ( int float -- float ) ( float int -- float )
  ( float float -- float )
	Pops 2 numbers and pushes the division of the two.
: name < a b c -- d e f > ( -- )
	Declares a function called 'name' that requires 3 items be on the stack of
	types 'a', 'b', and 'c', with 'c' at the top, and when it finishes, leaves 3
	items in their place of types 'd', 'e', and 'f', with 'f' at the top. Also
	creates a new scope. Note: this includes the '<', '>', and '--' built-ins.
; ( -- )
	Marks the end of a function definition and it's scope.
swap ( *1 *2 -- *2 *1 )
	Swaps the top 2 items on the stack.
dup ( *1 -- *1 *1 )
	Duplicates the top item on the stack.
if else end ( * -- *... )
	Conditional, if the provided value is true then all keywords between 'if'
	and 'else' are executed, else all keywords between 'else' and 'end' are.
if end ( * -- *... )
	Short form without an 'else' branch.
Toy language that is a mix of Forth[1] and Magpie[2]. Combines mostly
concatenative syntax and stack-based programming with a relatively simple type
system and multi-methods.

[1] https://en.wikipedia.org/wiki/Forth_(programming_language)
[2] https://magpie-lang.org/index.html

# SYNTAX OVERVIEW

\ this is a line comment
( this is a block comment ( they nest ) )

\ integer literals
123 -123 123u 123ul -123l

\ float literals
1.23 -1.23 .123 -.123 1.23d

\ string literals
"hello there!"

\ conditional
<condition> if <iftrue> end
<condition> if <iftrue> else <iffalse> end

\ conditional loop
while <condition> do <body> end
until <condition> do <body> end

\ iteration
<n> repeat <body> end
<start> <end> loop <body> end
<start> <end> <step> sloop <body> end

\ variables
var <name> \ create
= <name> \ assign

\ functions
fn [{ <types> }] <name> [{ <returns> }] <body> end
\ example (fibonacci)
fn { num } fib { num }
	dup 1 <= if drop 1 else 1 - dup fib swap 1 - fib + end
end

\ blocks for containing locals
do <body> end

\ types
type <name> [{ <interits> }]
	<name> : <type> \ member
	[...]
end

# HELLO WORLD

"hello world!" prln

M design => design +2 -5
@@ 11,7 11,7 @@
\ if
<condition> if <iftrue> [else <iffalse>] end
\ while/until
<condition> while|until <body> end
while|until <condition> do <body> end
\ iota
<n> repeat <body> end
<start> <end> loop <body> end


@@ 29,18 29,15 @@ var <name>

\ function
fn [{ <types> }] <name> [{ <returns> }] <body> end
\ anonymous function (for loops etc.)
{ <body> }

\ block
do <body> end

\ types
type <name> <members> end
type <name> [{ <inherits> }] <members> end
	\ member
	<name> : <type>


\ macro system ( possibly )
\ example declaring variables `a` to `e`
%[ 0 5 loop var i "var" "abcde" [i] end ]%

M lexer.d => lexer.d +10 -0
@@ 67,6 67,16 @@ struct Lexer {
			case '\\' : // line comment
				while ( step() != '\n' && ! atEnd ) { }
				break ;
			case '(' : // block comment
				ulong level = 1 ;
				while ( ! atEnd ) {
					if ( match( '(' ) ) level ++ ;
					else if ( match( ')' ) ) {
						level -- ;
						if ( level == 0 ) break ;
					} else step() ;
				}
				break ;
			// whitespace
			case ' ' : case '\t' : case '\r' : case '\n' : break ;
			// string