Skip to content

Commit

Permalink
Improved compiler
Browse files Browse the repository at this point in the history
  • Loading branch information
joeldrapper committed Oct 25, 2022
1 parent c2c0432 commit 6f6ef25
Show file tree
Hide file tree
Showing 31 changed files with 728 additions and 239 deletions.
6 changes: 6 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@ inherit_from:

AllCops:
TargetRubyVersion: 2.7

Style/PercentLiteralDelimiters:
Enabled: false

Layout/CaseIndentation:
Enabled: false
6 changes: 6 additions & 0 deletions bench.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@

puts RUBY_DESCRIPTION

a = Example::Page.new.call
Example::Page.compile
b = Example::Page.new.call

raise unless a == b

Benchmark.ips do |x|
x.report("Page") { Example::Page.new.call }
end
58 changes: 58 additions & 0 deletions fixtures/compilation/method_add_block.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# frozen_string_literal: true

module Fixtures
module Compilation
module MethodAddBlock
class WithBareString < Phlex::View
def template
h1 { "Hello" }
end
end

class WithSymbol < Phlex::View
def template
h1 { :hello }
end
end

class WithFloat < Phlex::View
def template
h1 { 1.2 }
end
end

class WithInteger < Phlex::View
def template
h1 { 1 }
end
end

class WithVariable < Phlex::View
def template
greeting = "Hello"
h1 { greeting }
end
end

class WithInstanceVariable < Phlex::View
def template
h1 { @hello }
end
end

class WithNestedTags < Phlex::View
def template
article {
h1 { "Inside" }
}
end
end

class WithArguments < Phlex::View
def template
h1(class: "hello") { "Hello" }
end
end
end
end
end
42 changes: 17 additions & 25 deletions fixtures/page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,28 @@
module Example
class Page < Phlex::View
def template
render LayoutComponent.new do
h1 { "Hi" }
h1 { "Hi" }

5.times do
div do
10.times do
a(href: "something", unique: SecureRandom.uuid, data: { value: 1 }) { "Test" }
end
table id: "test", class: "a b c d e f g" do
tr do
td id: "test", class: "a b c d e f g" do
span { "Hi" }
end

td id: "test", class: "a b c d e f g" do
span { "Hi" }
end

td id: "test", class: "a b c d e f g" do
span { "Hi" }
end
end

table do
thead do
10.times do
tr do
th { "Hi" }
end
end
td id: "test", class: "a b c d e f g" do
span { "Hi" }
end

tbody do
100.times do
tr class: "a b c d e f g", id: "something" do
10.times do
td class: "f g h i j k l" do
span { "Test" }
end
end
end
end
td id: "test", class: "a b c d e f g" do
span { "Hi" }
end
end
end
Expand Down
10 changes: 8 additions & 2 deletions lib/phlex/compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,21 @@ def call
Visitors::File.new(self).visit(tree)
end

def tag_method?(method_name)
(HTML::STANDARD_ELEMENTS.key?(method_name) || HTML::VOID_ELEMENTS.key?(method_name)) && !redefined?(method_name)
end

def redefined?(method_name)
prototype = @view.allocate

@view.instance_method(method_name).bind(prototype) !=
Phlex::View.instance_method(method_name).bind(prototype)
end

def redefine(method)
@view.class_eval(method)
def redefine(method, line:)
print method
print "\n\n"
@view.class_eval(method, file, line)
end

def line
Expand Down
49 changes: 49 additions & 0 deletions lib/phlex/compiler/elements.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

module Phlex::Compiler::Elements
module VCall
def format(formatter)
Phlex::Compiler::Generators::Element.new(
Phlex::Compiler::Nodes::VCall.new(self),
formatter: formatter
).call
end
end

module FVall
def format(formatter)
Phlex::Compiler::Generators::Element.new(
Phlex::Compiler::Nodes::FVall.new(self),
formatter: formatter
).call
end
end

module Command
def format(formatter)
Phlex::Compiler::Generators::Element.new(
Phlex::Compiler::Nodes::Command.new(self),
formatter: formatter
).call
end
end

module MutatingMethodAddBlock
def format(formatter)
Phlex::Compiler::Generators::Element.new(
Phlex::Compiler::Nodes::MethodAddBlock.new(self),
formatter: formatter,
mutating: true
).call
end
end

module MethodAddBlock
def format(formatter)
Phlex::Compiler::Generators::Element.new(
Phlex::Compiler::Nodes::MethodAddBlock.new(self),
formatter: formatter
).call
end
end
end
97 changes: 97 additions & 0 deletions lib/phlex/compiler/generators/content.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# frozen_string_literal: true

module Phlex
class Compiler
module Generators
class Content
def initialize(formatter, content:, mutating: false)
@formatter = formatter
@content = content
@mutating = mutating
end

def call
return if nil_value?
return bare_string_value if bare_string_value?
return symbol_value if symbol_value?
return numeric_value if numeric_value?
return variable_value if variable_value?

unknown_value
end

private

def nil_value?
@content in SyntaxTree::VarRef[value: SyntaxTree::Kw[value: "nil"]]
end

def bare_string_value?
@content in SyntaxTree::StringLiteral[
parts: [
SyntaxTree::TStringContent
]
]
end

def symbol_value?
@content in SyntaxTree::SymbolLiteral
end

def numeric_value?
@content in SyntaxTree::Int | SyntaxTree::FloatLiteral
end

def variable_value?
@content in SyntaxTree::VarRef
end

def bare_string_value
@formatter.append do |f|
f.text CGI.escape_html(
@content.parts.first.value
)
end
end

def symbol_value
@formatter.append do |f|
f.text CGI.escape_html(
@content.value.value
)
end
end

def numeric_value
@formatter.append do |f|
f.text CGI.escape_html(
@content.value
)
end
end

def variable_value
@formatter.chain_append do |f|
f.text "CGI.escape_html("
@content.format(f)
f.text ")"
end
end

def unknown_value
@formatter.breakable(force: true)
if @mutating
@content.format(@formatter)
else
@formatter.text "yield_content {"
@formatter.breakable(force: true)
@content.format(@formatter)
@formatter.breakable(force: true)
@formatter.text "}"
end
@formatter.breakable(force: true)
end
end
end
end
end
60 changes: 60 additions & 0 deletions lib/phlex/compiler/generators/element.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# frozen_string_literal: true

module Phlex
class Compiler
module Generators
class Element
def initialize(node, formatter:, mutating: false)
@node = node
@formatter = formatter
@mutating = mutating
end

def call
@formatter.append do |f|
f.text "<"
f.text tag
end

if @node.arguments&.parts&.any?
@formatter.chain_append do |f|
f.text "fetch_attrs("
@node.arguments.format(@formatter)
f.text ")"
end
end

@formatter.append do |f|
f.text ">"
end

return if void?

if @node.content
if @node.content in SyntaxTree::Statements[body: [c]]
Content.new(@formatter, content: c, mutating: @mutating).call
else
@node.content.format(@formatter)
end
end

@formatter.append do |f|
f.text "</"
f.text tag
f.text ">"
end
end

private

def tag
HTML::STANDARD_ELEMENTS[@node.name] || HTML::VOID_ELEMENTS[@node.name]
end

def void?
HTML::VOID_ELEMENTS.key?(@node.name)
end
end
end
end
end
30 changes: 0 additions & 30 deletions lib/phlex/compiler/generators/standard_element.rb

This file was deleted.

Loading

0 comments on commit 6f6ef25

Please sign in to comment.