Skip to content

Commit

Permalink
Merge pull request rouge-ruby#651 from katafrakt/pony
Browse files Browse the repository at this point in the history
Add lexer for Pony
  • Loading branch information
jneen authored Apr 19, 2017
2 parents 4f8af3c + ce5baf6 commit 3060552
Show file tree
Hide file tree
Showing 4 changed files with 308 additions and 0 deletions.
17 changes: 17 additions & 0 deletions lib/rouge/demos/pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use "ponytest"

actor Main is TestList
new create(env: Env) => PonyTest(env, this)
new make() => None

fun tag tests(test: PonyTest) =>
test(_TestAddition)

class iso _TestAddition is UnitTest
"""
Adding 2 numbers
"""
fun name(): String => "u32/add"

fun apply(h: TestHelper): TestResult =>
h.expect_eq[U32](2 + 2, 4)
93 changes: 93 additions & 0 deletions lib/rouge/lexers/pony.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# -*- coding: utf-8 -*- #

module Rouge
module Lexers
class Pony < RegexLexer
tag 'pony'
filenames '*.pony'

keywords = %w(
actor addressof and as
be break
class compiler_intrinsic consume continue
do
else elseif embed end error
for fun
if ifdef in interface is isnt
lambda let
match
new not
object
primitive
recover repeat return
struct
then this trait try type
until use
var
where while with
)

capabilities = %w(
box iso ref tag trn val
)

types = %w(
Number Signed Unsigned Float
I8 I16 I32 I64 I128 U8 U32 U64 U128 F32 F64
EventID Align IntFormat NumberPrefix FloatFormat
Type
)

state :whitespace do
rule /[\s\t\r\n]+/m, Text
end

state :root do
mixin :whitespace
rule /"""/, Str::Doc, :docstring
rule %r{//(.*?)\n}, Comment::Single
rule %r{/(\\\n)?[*](.|\n)*?[*](\\\n)?/}, Comment::Multiline
rule /"/, Str, :string
rule %r([~!%^&*+=\|?:<>/-]), Operator
rule /(true|false|NULL)\b/, Name::Constant
rule %r{(?:[A-Z_][a-zA-Z0-9_]*)}, Name::Class
rule /[()\[\],.';]/, Punctuation

# Numbers
rule /0[xX]([0-9a-fA-F_]*\.[0-9a-fA-F_]+|[0-9a-fA-F_]+)[pP][+\-]?[0-9_]+[fFL]?[i]?/, Num::Float
rule /[0-9_]+(\.[0-9_]+[eE][+\-]?[0-9_]+|\.[0-9_]*|[eE][+\-]?[0-9_]+)[fFL]?[i]?/, Num::Float
rule /\.(0|[1-9][0-9_]*)([eE][+\-]?[0-9_]+)?[fFL]?[i]?/, Num::Float
rule /0[xX][0-9a-fA-F_]+/, Num::Hex
rule /(0|[1-9][0-9_]*)([LUu]|Lu|LU|uL|UL)?/, Num::Integer

rule /[a-z_][a-z0-9_]*/io do |m|
match = m[0]

if capabilities.include?(match)
token Keyword::Declaration
elsif keywords.include?(match)
token Keyword::Reserved
elsif types.include?(match)
token Keyword::Type
else
token Name
end
end
end

state :string do
rule /"/, Str, :pop!
rule /\\([\\abfnrtv"']|x[a-fA-F0-9]{2,4}|[0-7]{1,3})/, Str::Escape
rule /[^\\"\n]+/, Str
rule /\\\n/, Str
rule /\\/, Str # stray backslash
end

state :docstring do
rule /"""/, Str::Doc, :pop!
rule /\n/, Str::Doc
rule /./, Str::Doc
end
end
end
end
13 changes: 13 additions & 0 deletions spec/lexers/pony_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# -*- coding: utf-8 -*- #

describe Rouge::Lexers::Pony do
let(:subject) { Rouge::Lexers::Pony.new }

describe 'guessing' do
include Support::Guessing

it 'guesses by filename' do
assert_guess :filename => 'foo.pony'
end
end
end
185 changes: 185 additions & 0 deletions spec/visual/samples/pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/*
This file is copied from official Pony examples at:
https://github.com/ponylang/ponyc/blob/master/examples/mandelbrot/mandelbrot.pony
*/

use "files"
use "options"
use "collections"

actor Worker
new mandelbrot(main: Main, x: USize, y: USize, width: USize,
iterations: USize, limit: F32, real: Array[F32] val,
imaginary: Array[F32] val)
=>
var view: Array[U8] iso =
recover
Array[U8]((y - x) * (width >> 3))
end

let group_r = Array[F32].>undefined(8)
let group_i = Array[F32].>undefined(8)

var row = x

try
while row < y do
let prefetch_i = imaginary(row)

var col: USize = 0

while col < width do
var j: USize = 0

while j < 8 do
group_r.update(j, real(col + j))
group_i.update(j, prefetch_i)
j = j + 1
end

var bitmap: U8 = 0xFF
var n = iterations

repeat
var mask: U8 = 0x80
var k: USize = 0

while k < 8 do
let r = group_r(k)
let i = group_i(k)

group_r.update(k, ((r * r) - (i * i)) + real(col + k))
group_i.update(k, (2.0 * r * i) + prefetch_i)

if ((r * r) + (i * i)) > limit then
bitmap = bitmap and not mask
end

mask = mask >> 1
k = k + 1
end
until (bitmap == 0) or ((n = n - 1) == 1) end

view.push(bitmap)

col = col + 8
end
row = row + 1
end

main.draw(x * (width >> 3), consume view)
end

actor Main
var iterations: USize = 50
var limit: F32 = 4.0
var chunks: USize = 16
var width: USize = 16000
var actors: USize = 0
var header: USize = 0
var real: Array[F32] val = recover Array[F32] end
var imaginary: Array[F32] val = recover Array[F32] end
var outfile: (File | None) = None

new create(env: Env) =>
try
arguments(env)

let length = width
let recip_width = 2.0 / width.f32()

var r = recover Array[F32](length) end
var i = recover Array[F32](length) end

for j in Range(0, width) do
r.push((recip_width * j.f32()) - 1.5)
i.push((recip_width * j.f32()) - 1.0)
end

real = consume r
imaginary = consume i

spawn_actors()
create_outfile()
end

be draw(offset: USize, pixels: Array[U8] val) =>
match outfile
| let out: File =>
out.seek_start(header + offset)
out.write(pixels)
if (actors = actors - 1) == 1 then
out.dispose()
end
end

fun ref create_outfile() =>
match outfile
| let f: File =>
f.print("P4\n " + width.string() + " " + width.string() + "\n")
header = f.size()
f.set_length((width * (width >> 3)) + header)
end

fun ref spawn_actors() =>
actors = ((width + (chunks - 1)) / chunks)

var rest = width % chunks

if rest == 0 then rest = chunks end

var x: USize = 0
var y: USize = 0

for i in Range(0, actors - 1) do
x = i * chunks
y = x + chunks
Worker.mandelbrot(this, x, y, width, iterations, limit, real, imaginary)
end

Worker.mandelbrot(this, y, y + rest, width, iterations, limit, real,
imaginary)

fun ref arguments(env: Env) ? =>
let options = Options(env.args)

options
.add("iterations", "i", I64Argument)
.add("limit", "l", F64Argument)
.add("chunks", "c", I64Argument)
.add("width", "w", I64Argument)
.add("output", "o", StringArgument)

for option in options do
match option
| ("iterations", let arg: I64) => iterations = arg.usize()
| ("limit", let arg: F64) => limit = arg.f32()
| ("chunks", let arg: I64) => chunks = arg.usize()
| ("width", let arg: I64) => width = arg.usize()
| ("output", let arg: String) =>
outfile = try File(FilePath(env.root as AmbientAuth, arg)) end
| let err: ParseError => err.report(env.out) ; usage(env) ; error
end
end

fun tag usage(env: Env) =>
env.out.print(
"""
mandelbrot [OPTIONS]
The binary output can be converted to a BMP with the following command
(ImageMagick Tools required):
convert <output> JPEG:<output>.jpg
Available options:
--iterations, -i Maximum amount of iterations to be done for each pixel.
Defaults to 50.
--limit, -l Square of the limit that pixels need to exceed in order
to escape from the Mandelbrot set.
Defaults to 4.0.
--chunks, -c Maximum line count of chunks the image should be
divided into for divide & conquer processing.
Defaults to 16.
--width, -w Lateral length of the resulting mandelbrot image.
Defaults to 16000.
--output, -o File to write the output to.
"""
)

0 comments on commit 3060552

Please sign in to comment.