-
Notifications
You must be signed in to change notification settings - Fork 5
Getting Started
Pranay Prakash edited this page Aug 31, 2020
·
3 revisions
Note: Since github markdown doesn't have support for browse just yet, we're using the bash syntax highlighter below which works pretty well for the comments but does cause a bunch of other issues, so don't get confused by the coloring below
# There's only one type of comment, and that's single line comments that start with '#'
# you can just add multiple of these
# if you want
# multiline comments
# A browse program consists of Rules (similar to a Statement in other languages)
# Rules are separated by newlines (or ;)
# To split a rule into multiple lines, you can end a line with \\
# You'll see that used later in this document. For now:
# A very simple built-in rule is called print, and it just prints its arguments to stdout
print hello world # prints "hello world" to the console
# You may be wondering why "hello world" isn't wrapped in quotes
# That's because browse supports implicit strings, just like bash.
# The very first word in a rule is always the rule name
# and all arguments after that are expressions. So, in the example
# above, "hello" and "world" are two strings passed as arguments to "print"
# There are 4 ways to represent strings in browse
print "double quotes, " \\
'single quotes, ' \\
`back ticks, ` \\
implicit strings and \\
|
multi
line
strings
|
# In addition to strings, there's also a few other literals like booleans, nil (like null in Java) and
# numbers (which are treated as IEEE double precision floating points and support scientific notation)
print true false nil 12 3.4 5e6 7.8e-9
# Here are some basic operators supported by browse
print 1 + 1 # = 2
print 0.1 + 0.2 # = 0.30000000000000004
print 8 - 1 # = 7
print 10 * 2 # = 20
print 35 / 5 # = 7
# Including uneven division.
print 5 / 2 # = 2.5
# And modulo division.
print 10 % 2 # = 0
print 30 % 4 # = 2
print 18.5 % 7 # = 4.5
# Precedence is enforced with parentheses.
print 1 + 3 * 2 # = 7
print (1 + 3) * 2 # = 8
# Negation uses the ! symbol
print !true # = false
print !false # = true
# Equality is ==
print 1 == 1 # = true
print 2 == 1 # = false
# Inequality is !=
print 1 != 1 # = false
print 2 != 1 # = true
# Comparisons
print 1 < 10 # = true
print 1 > 10 # = false
print 2 <= 2 # = true
print 2 >= 2 # = true
# Logical AND and OR
print 1 < 10 && 11 < 10 # = false
print 1 < 10 || 11 < 10 # = true
print 0 && 1 # = 0
print 0 || 1 # = 1
print 1 || 2 # = 1
# Strings are concatenated with +
print "Hello " + "world!" # = "Hello world!"
# While parentheses is used to control precedence (as shown previously),
# it has a special meaning when the first value between the parentheses is a rule name.
# In that case, it actually evaluates the rule enclosed in parentheses.
# i.e. every Rule in browse is not just a statement, but also an expression that can evaluate
# to a value
print (print 12) # will print "12" followed by "12" again (which is the return value of print)
# To define variables in browse, simply use the "set" rule
set x 12
# And to get the value of a variable, use prepend the variable name a '$'
print $x # => 12
# browse has one more additional datatype called a RuleSet. We'll cover this in detail in the advanced guide
# but for now, just know that a RuleSet is a list of Rules seperated by ';' or a newline and
# is enclosed in braces ({ ... })
print { print I am in a RuleSet }
# To define a custom rule, we use a rule aptly named `rule`
# The arguments to `rule` are a string (the rule's name) and a RuleSet (body)
# `fun` creates a new rule using the name you passed in
rule sayHello {
print hello world
}
# When the rule is triggered, the `body` RuleSet is evaluated
sayHello # prints hello world to the terminal
# There are two special rules that are available within a the body of a function - `bind` and `return`:
# bind takes a list of strings as arguments, and for each string, it will create a variable
# with that string as the name, bound to the corresponding argument passed to the rule
# when called. In other words, this is how your function receives parameters.
# return just takes one argument and sets the return value of the Rule to that value
rule double { bind x ; return $x + $x }
print (double 1) # => 2
# A quick note on `return`. It doesn't work exactly like in other languages - i.e. calling return early
# won't cause the RuleSet to stop execution early, so the rest of the rule will still be evaluated.
# In reality, the last Rule in the `body` is what the entire rule evaluates to, and `return` is
# just an alias for `id`, the identity rule. Read the API Reference for more details
# Rules can also take named arguments, called options, which is heavily inspired by bash programs
# that take options via flags (-f or --help). Options should only be used for optional
# arguments (required ones are povided as positionals) and a rule can be called with options
# by using `(...)` immediately after the rule name (without a space).
# The syntax is `option=value`, and simply saying `option` is the same as `option=true`
# futher `!option` means `option=false`
my_rule(double !yell prefix="Ans: ") 2 # This sets `double` to true, `yell` to false, and `prefix` to "Ans: "
# Let's now define that rule `my_rule` for completeness
rule my_rule {
bind(double triple yell prefix) num # unbound options are set to `nil`
set out ""
if $prefix then { set out $prefix }
if $double then { set out $out + num * 2 } else {
if $triple then { set out $out + num * 3 } else { set out $out + num }
}
# if yell is not explicitly set to false, we always yell!
if $yell != false then { set out $out + "!!!" }
print $out
}
# If you're wondering why everything seems a lot more complicated than a language that has a native
# function definition syntax, browse chose this because it lets library authors design very
# expressive rules that "feel" like they're a part of the language. The RuleSet pattern is
# really powerful. For example, `if` and `for` are implemented as Rules in browse and they feel
# like they belong in the language. In the examples folder on the windsorio/browse repo, you'll see
# an example of a `while` rule that adds a syntax for a `while` loop that's implemented in just
# 6 lines of browse!!
# "if" is a built in rule that takes 3 or 5 arguments.
# note: the "then" and "else" here are not special keywords in browse, these are just strings.
# This improves code readability and they serve no other purpose
# 3 args : if (...) then { ... }
# 5 args : if (...) then { ... } else { ... }
if ((double 1) == 2) then {
print browse is awesome
} else {
print browse sucks
}# This code should be fairly self explanatory. However, just note that the first argument to the "if" rule
# i.e. the condition that is tested, does not need to be wrapped in parentheses. It accepts any expression at all
# and we use the parentheses for readability. This is perfectly valid too
if 2 == 2 then { print browse is awesome } else { print browse sucks }
# also, the "if" rule evaluates to the value of whichever RuleSet it ends up evaluating
# this lets you use "if" as a ternary expression
print (if true then { double 1 } else { double 2 }) # => prints 2 to the console
# the "for" loop in browse is also implemented as a rule. This is one of those times where we harness
# the special powers of a RuleSet. Here is a simple example
for { set i 2 ; test $i < 5 ; set i $i+1 } {
print loop $i
}
# You should know enough about browse now, but if you'd like to learn how `for` takes advantage of
# RuleSets being a data structure in browse, read on.
# for takes 2 arguments, the iterator RuleSet, and the loop body RuleSet
# While the loop body RuleSet works just like the previous RuleSets we've seen
# The iterator is interesting, because "for" doesn't just evaluate the RuleSet sequentially
# Instead, it breaks apart the RuleSet:
# 1. First, the it evaluates the very first rule. This is the loop's initializer
# 2. Then, it runs every rule, up till but excluding the very last rule.
# There's a special rule available in this step called `test`.
# If the argument passed to test is falsy, the loop ends
# The iterator RuleSet can support more than just three Rules, and can even refer to rules
# beside "test". ex: for { set i 0 ; print $i ; test $i < 5 ; set i $i+1 } ...
# 3. The body of the for loop is evaluated (i.e. the second argument)
# 4. Finally, the iterator rule (i.e. the last Rule in the iterator RuleSet) is evaluated
# 5. Repeat from step 2 Check out the other pages of this wiki to learn the more advanced rules, how to write your own custom rules, and more.
Additionally, check out the examples directory in the repo to see some neat examples of using what you've learnt here in real browse programs