Skip to content

Instantly share code, notes, and snippets.

@devyn
Created October 23, 2009 08:17
Show Gist options
  • Save devyn/216743 to your computer and use it in GitHub Desktop.
Save devyn/216743 to your computer and use it in GitHub Desktop.
# Distributed OS, Language Prototype II (Treetop)
# With Documentation
require 'rubygems'
require 'treetop'
module DiOS
grammar LangProto2
# The main scope of a file. It's also the body of a thing!
rule ether
thing_body
end
# Anything. Can be an "atom," "thing," or "action."
rule anything
atom / thing / action
end
# See thing_body
rule thing
'(' thing_body ')'
end
# [ ... ] is for expressions
# %[ ... ] is for closures
rule action
'%[' action_body ']' /
'[' action_body ']'
end
# Holy crap. Okay, so, let me give a few definitions here:
# ----------------------
# nil (or null) is a thing with no value. like a void.
# true (or yes) is sorta like a proton. it has a positive charge.
# false (or no) is like an electron. it has a negative charge.
# ----------------------
# IMPORTANT: The only values considered negative are nil and false. Like Ruby.
# ----------------------
# self refers to the current scope. can often be omitted (like watashi in Japanese).
# ^ refers to the arguments passed to this scope. only for closures and their children. if no arguments were passed, returns ().
# \ refers to the top level scope (or 'ether'). for example: [\ system] -- refers to the "system" message of the ether.
# !! is a special message. See the note for it in "message" for more information.
# obviously, numbers are allowed. decimal: 73_891_033 octal: 0755 hexadecimal: 0xDEAD binary: 0b10010110
# strings: "#[name] is a #[fruit]" or 'I am dead' (similar rules to Ruby)
# regexp: Same as Ruby, without of the 'o' flag.
# word: like an Erlang 'atom.' most useful for message passing.
rule atom
('nil' / 'null')
/ ('true' / 'yes')
/ ('false' / 'no')
/ 'self'
/ '^'
/ "\\"
/ "!!"
/ ("0" [0-7]+ / "0x" [0-9A-Fa-f]+ / "0b" [01]+ / [0-9_]+)
/ '"' (action_embed / escape_code / !'"' .)+ '"'
/ "'" ("\\\\" / "\\'" / "\\" . / !"'" .)+ "'"
/ "/" rxp_body "/" rxp_flag*
/ [A-Za-z_] [A-Za-z0-9_]*
end
# NOTE: Repeating [+-*/] means "make it permanent," like [+-*/] '=' in a lot of languages.
# Example: player points ++ 10
# (ruby) player.points += 10
# NOTE: Messages are by default passed to "self." If the message gets no response in "self," the parent scope is tried.
# If you want to be sure you're sending a message to the top level, you can use "\"
# If nothing responds to a message, an error will be issued.
# NOTE: Errors, return focus, etc.
# The "->" or "return value" operator does *not* return focus to the caller. Instead it just sets the return value. That's all.
# Because of this, the "!!" special message has a few interesting behaviours.
# 1) Return focus / jumping: "!!" by itself, with no parameters, will immediately return to the caller. Example:
# -> ^ base exp([^ exponent];). !!. -- return "base to the power of exponent" and jump to caller
# 2) Errors: "!!(error: (code: <atom> description: <atom>))" will not only return to the caller,
# but also send an error to the caller. Example:
# raise_error: %[
# !!(error: (code: IntentionalError description: "This error was intentionally set."))
# ]
# 3) Error handling: Yes, the error message itself also handles errors. Example:
# !!(
# try: %[
# -- error prone code goes here
# ]
# fail: (
# RuntimeError: %[
# -- respond to errors with code RuntimeError (can also be a list-thing)
# ]
# nil: %[
# -- respond to any other errors not mentioned above
# ]
# )
# ensure: %[
# -- optionally, what you want to make sure (no matter what) gets run.
# ]
# )
# NOTE: On arguments... The argument message "^" returns the thing that was passed to this closure.
# If there are no arguments to this scope, the parent scope is tried, and so on.
# If no arguments can be found, this is equal to "nil"
# NOTE: Argument from existing thing:
# send: %[^ object [^ message][^ arguments]]
# [send(object: [console] message: out arguments: (line: "Hello, world!"))]
# NOTE: Mixins are used to do pretty much everything... (by default the "system defaults" thing is mixed in to everything)
# to mix a thing into another thing:
#
# [self ++[HTTP Server]]. -- extend / mix in "HTTP Server"
# [self ++(property: value)]. -- mix in (property: value) which is the standard way of adding a message dynamically,
# could also be shortened to ++(property: value). in the middle of an action.
#
# example:
# [system defaults ++(
# send: %[
# ^ require( message; ).
# self [^ at(index: 1)][^ at(start: 2 end: -1)].
# ]
# ].
# [console send(out; line: "Hello, world!")].
rule message
(
anything (thing/action)? /
([+-*/] [+-*/]? / [<>=!&|] '='? / "&&" / "||") whitespace? anything
) /
(whitespace &(message) / "")
end
# any length of messages, optionally with the "return value" operator.
rule messages
whitespace? ('->' whitespace?)? message+ whitespace?
end
# NOTE: (x: nil) is equal to (x;)
# Just a bit of syntactic sugar for lists :D
# (
# message1: "Hello, world!"
# "AAAA";
# [].
# )
rule thing_body
whitespace?
(
whitespace?
anything ':' whitespace?
anything
whitespace?
/
whitespace?
anything ';'
whitespace?
/
whitespace?
anything '.'
whitespace?
)*
whitespace?
end
# Message lists separated by periods. Optionally,
# you may have a period at the last message list, but it isn't required.
# It may or may not make your code look better, and depends on your style.
rule action_body
whitespace? messages:(messages ('.' whitespace? &messages / '.'?))+ whitespace?
end
# Well, actually, comments count as whitespace as well :D
rule whitespace
(block_comment / line_comment / [\s]+)+
end
# --[ block comments can appear anywhere ]--
rule block_comment
"--[" (!"]--" .)* "]--"
end
# -- line comments can only appear at the ends of lines.
rule line_comment
"--" [^\n]*
end
# Standard escape codes you should be familiar with. Moving on...
rule escape_code
"\\" (
[\\"abrnstfe] /
"x" [0-9A-Fa-f] [0-9A-Fa-f] /
[0-7] [0-7] [0-7] /
.
)
end
# Like #{ ... } in Ruby, we use #[ ... ]. Duh!
rule action_embed
'#[' action_body ']'
end
# Standard regexp syntax. A few weird quirks are in here, and need to be ironed out.
rule rxp_body
(
rxp_escape_code /
"[" (
(rxp_escape_code / [^/])
'-'
(rxp_escape_code / [^/])
)* "]" /
"(" rxp_body ")" /
"{" [0-9]+ ("," [0-9]+)? "}" /
"\\Q" (rxp_escape_code / !"\\E" !'/' .)* "\\E" /
[*+?] /
[\^$] /
"|" /
(!"/" .)+
)*
end
# Regexp escapes.
rule rxp_escape_code
"\\" (
[\\/arnstfe] /
[\[\^$.|?*+(){}\]] /
[dDsSwWbBAZ] /
"x" [0-9A-Fa-f] [0-9A-Fa-f] /
[0-7] [0-7] [0-7] /
.
)
end
# Regexp flags. i, m, and x. Equal to Ruby.
rule rxp_flag
[imx]
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment