A mini-language in Ruby
Our Metaphor

Our Metaphor

John Underwood
- CS at UT
- Love languages
- Love helping people
- Live coding
Motivation
- Small, but growing in complexity
- or
- Needs to be consistent
The Parts

The Parts
[
{ field: "start_at", data: "= 01/12/2016 || = 01/27/2016" },
{ field: "amount", data: "> 200" }
][
{ field: "start_at", data: "= 01/12/2016 || = 01/27/2016"},
{ field: "amount", data: "> 200"}
][
{ field: "start_at", data: { or: [{ op: :eq, data: "01/12/2016"},
{ op: :eq, data: "01/27/2016"}] } } },
{ field: "amount", data: { { op: :gt, data: "200"} }
][
{ field: "start_at", data: { or: [{ op: :eq, data: "01/12/2016"},
{ op: :eq, data: "01/27/2016"}] } },
{ field: "amount", data: { { op: :gt, data: "200"} }
][
{ field: "start_at", data: { or: [{ op: :eq, data: "01/12/2016"},
{ op: :eq, data: "01/27/2016"}] } },
{ field: "amount", data: { { op: :gt, data: "200"} }
]SELECT *
FROM scholarships
WHERE
(start_at = '2016-01-12' OR start_at = '2016-01-27') AND amount > 200[
{ field: "start_at", data: { or: [{ op: :eq, data: "01/12/2016"},
{ op: :eq, data: "01/27/2016"}] } },
{ field: "amount", data: { { op: :gt, data: "200"} }
]table = Scholarship.arel_table
Scholarship.where(
table.grouping(
table[:start_at].eq('01/12/2016').or((table[:start_at].eq('01/27/2016'))
).and(table[:amount].gt(200))))
[
{ field: "start_at", data: { or: [{ op: :eq, data: "01/12/2016"},
{ op: :eq, data: "01/27/2016"}] } },
{ field: "amount", data: { { op: :gt, data: "200"} }
]{ and: [{ or: [{ from: "01/12/2016 06:00:00 UTC", to: "01/13/2016 05:59:59 UTC",
include_lower: true, include_upper: true },
{ from: "01/27/2016 06:00:00 UTC", to: "01/28/2016 05:59:59 UTC",
include_lower: true, include_upper: true } ] },
{ range: {"amount" => {gt: "200" } } } ] }
The Source Code
Source Code
|| - Logical OR
= - Includes
< - Less than
<= - Less than or equal to
> - Greater than
>= - Greater than or equal toThe AST
{ op: :eq, data: '4'}
{ op: :gt, data: '01/01/2015' }
{ or: [
{ op: :eq, data: '4'},
{ op: :eq, data: '6'}
]
}The Parser
The SQL Compiler
The AREL Compiler
The AREL API
class Scholarship < ActiveRecord::Base
end
1 arel_table = Scholarship.arel_table
2 Scholarship.where(start_at: Date.today) # Active Record
3 clause = arel_table[:start_at].eq(Date.today) # AREL
4 Scholarship.where(clause) # Using AREL
5 before_today_clause = arel_table[:start_at].lte(Date.today) # Less than
6 amount_clause = arel_table[:amount].gt(500) # Greater than
7 combined_clause = before_today_clause.or(amount_clause) # combine
8 Scholarship.where(combined_clause) # Using ARELThe ElasticSearch Compiler
The ElasticSearch API
{ "term" => { "amount" => "2000" } }
{ "term" => { "start_at" => { "gt" => "2016-01-13 06:00:00 UTC" } } }
{ "term" => { "amount" => { "lt" => "5000" } } }
{ "or" => [
{ "term" => { "amount" => { "lt" => "5000" } } },
{ "term" => { "start_at" => { "gt" => "2016-01-13 06:00:00 UTC" } } }
]
}Tying it all together
Uh, now what
Where did we go from here?
Parser Grammer
expression ::= <comparison> (|| <comparison>)*
comparison ::= (<>|<|<=|>|>=|=)? <value>
value ::= number | dateParsers
- rexical and racc
- Treetop
- parselet
Compiling
- AREL uses visitor pattern
- LLVM
Compilers
- Create Your Own Programming Language
- Compilers: Principles, Techniques, and Tools
- PL (http://lisperator.net/pltut/) (in javascript)
- MRI, rubinius, etc
The return of why
Thank you
Tradukilo
By kircxo
Tradukilo
- 579