diff options
author | Georg Brandl <georg@python.org> | 2015-08-08 07:07:10 +0200 |
---|---|---|
committer | Georg Brandl <georg@python.org> | 2015-08-08 07:07:10 +0200 |
commit | f3817e5d42209595fa787ef81814a8deedfb40ec (patch) | |
tree | 5da9b02514aa1c4da31ce5b808f46825fcde43f5 /tests/examplefiles | |
parent | 62ed942986ae720e1df237c7d96700e93a2aaa11 (diff) | |
parent | 151707358274accc260f64e590879f8cd8b77465 (diff) | |
download | pygments-f3817e5d42209595fa787ef81814a8deedfb40ec.tar.gz |
Merged in ylikx/pygments-main (pull request #213)
Diffstat (limited to 'tests/examplefiles')
117 files changed, 21734 insertions, 2475 deletions
diff --git a/tests/examplefiles/99_bottles_of_beer.chpl b/tests/examplefiles/99_bottles_of_beer.chpl new file mode 100644 index 00000000..3629028d --- /dev/null +++ b/tests/examplefiles/99_bottles_of_beer.chpl @@ -0,0 +1,174 @@ +/*********************************************************************** + * Chapel implementation of "99 bottles of beer" + * + * by Brad Chamberlain and Steve Deitz + * 07/13/2006 in Knoxville airport while waiting for flight home from + * HPLS workshop + * compiles and runs with chpl compiler version 1.7.0 + * for more information, contact: chapel_info@cray.com + * + * + * Notes: + * o as in all good parallel computations, boundary conditions + * constitute the vast bulk of complexity in this code (invite Brad to + * tell you about his zany boundary condition simplification scheme) + * o uses type inference for variables, arguments + * o relies on integer->string coercions + * o uses named argument passing (for documentation purposes only) + ***********************************************************************/ + +// allow executable command-line specification of number of bottles +// (e.g., ./a.out -snumBottles=999999) +config const numBottles = 99; +const numVerses = numBottles+1; + +// a domain to describe the space of lyrics +var LyricsSpace: domain(1) = {1..numVerses}; + +// array of lyrics +var Lyrics: [LyricsSpace] string; + +// parallel computation of lyrics array +[verse in LyricsSpace] Lyrics(verse) = computeLyric(verse); + +// as in any good parallel language, I/O to stdout is serialized. +// (Note that I/O to a file could be parallelized using a parallel +// prefix computation on the verse strings' lengths with file seeking) +writeln(Lyrics); + + +// HELPER FUNCTIONS: + +proc computeLyric(verseNum) { + var bottleNum = numBottles - (verseNum - 1); + var nextBottle = (bottleNum + numVerses - 1)%numVerses; + return "\n" // disguise space used to separate elements in array I/O + + describeBottles(bottleNum, startOfVerse=true) + " on the wall, " + + describeBottles(bottleNum) + ".\n" + + computeAction(bottleNum) + + describeBottles(nextBottle) + " on the wall.\n"; +} + + +proc describeBottles(bottleNum, startOfVerse:bool = false) { + // NOTE: bool should not be necessary here (^^^^); working around bug + var bottleDescription = if (bottleNum) then bottleNum:string + else (if startOfVerse then "N" + else "n") + + "o more"; + return bottleDescription + + " bottle" + (if (bottleNum == 1) then "" else "s") + + " of beer"; +} + + +proc computeAction(bottleNum) { + return if (bottleNum == 0) then "Go to the store and buy some more, " + else "Take one down and pass it around, "; +} + + +// Modules... +module M1 { + var x = 10; +} + +module M2 { + use M1; + proc main() { + writeln("M2 -> M1 -> x " + x); + } +} + + +// Classes, records, unions... +const PI: real = 3.14159; + +record Point { + var x, y: real; +} +var p: Point; +writeln("Distance from origin: " + sqrt(p.x ** 2 + p.y ** 2)); +p = new Point(1.0, 2.0); +writeln("Distance from origin: " + sqrt(p.x ** 2 + p.y ** 2)); + +class Circle { + var p: Point; + var r: real; +} +var c = new Circle(r=2.0); +proc Circle.area() + return PI * r ** 2; +writeln("Area of circle: " + c.area()); + +class Oval: Circle { + var r2: real; +} +proc Oval.area() + return PI * r * r2; + +delete c; +c = nil; +c = new Oval(r=1.0, r2=2.0); +writeln("Area of oval: " + c.area()); + +// This is a valid decimal integer: +var x = 0000000000012; + +union U { + var i: int; + var r: real; +} + +// chapel ranges are awesome. +var r1 = 1..10, // 1 2 3 4 5 6 7 8 9 10 + r2 = 10..1, // no values in this range + r3 = 1..10 by -1, // 10 9 8 7 6 5 4 3 2 1 + r4 = 1..10 by 2, // 1 3 5 7 9 + r5 = 1..10 by 2 align 0, // 2 4 6 8 10 + r6 = 1..10 by 2 align 2, // 2 4 6 8 10 + r7 = 1..10 # 3, // 1 2 3 + r8 = 1..10 # -2, // 9 10 + r9 = 1..100 # 10 by 2, // 1 3 5 7 9 + ra = 1..100 by 2 # 10, // 1 3 5 7 9 11 13 15 17 19 + rb = 1.. # 100 by 10; // 1 11 21 31 41 51 61 71 81 91 + +// create a variable with default initialization +var myVarWithoutInit: real = noinit; +myVarWithoutInit = 1.0; + +// Chapel has <~> operator for read and write I/O operations. +class IntPair { + var x: int; + var y: int; + proc readWriteThis(f) { + f <~> x <~> new ioLiteral(",") <~> y <~> new ioNewline(); + } +} +var ip = new IntPair(17,2); +write(ip); + +var targetDom: {1..10}, + target: [targetDom] int; +coforall i in targetDom with (ref target) { + targetDom[i] = i ** 3; +} + +var wideOpen = 0o777, + mememe = 0o600, + clique_y = 0O660, + zeroOct = 0o0, + minPosOct = 0O1; + +private module M3 { + private proc foo() { + + } + + private iter bar() { + + } + + private var x: int; + +}
\ No newline at end of file diff --git a/tests/examplefiles/Blink.ino b/tests/examplefiles/Blink.ino new file mode 100644 index 00000000..993bd743 --- /dev/null +++ b/tests/examplefiles/Blink.ino @@ -0,0 +1,24 @@ +/* + Blink + Turns on an LED on for one second, then off for one second, repeatedly. + + This example code is in the public domain. + */ + +// Pin 13 has an LED connected on most Arduino boards. +// give it a name: +int led = 13; + +// the setup routine runs once when you press reset: +void setup() { + // initialize the digital pin as an output. + pinMode(led, OUTPUT); +} + +// the loop routine runs over and over again forever: +void loop() { + digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level) + delay(1000); // wait for a second + digitalWrite(led, LOW); // turn the LED off by making the voltage LOW + delay(1000); // wait for a second +} diff --git a/tests/examplefiles/Error.pmod b/tests/examplefiles/Error.pmod new file mode 100644 index 00000000..808ecb0e --- /dev/null +++ b/tests/examplefiles/Error.pmod @@ -0,0 +1,38 @@ +#pike __REAL_VERSION__ + +constant Generic = __builtin.GenericError; + +constant Index = __builtin.IndexError; + +constant BadArgument = __builtin.BadArgumentError; + +constant Math = __builtin.MathError; + +constant Resource = __builtin.ResourceError; + +constant Permission = __builtin.PermissionError; + +constant Decode = __builtin.DecodeError; + +constant Cpp = __builtin.CppError; + +constant Compilation = __builtin.CompilationError; + +constant MasterLoad = __builtin.MasterLoadError; + +constant ModuleLoad = __builtin.ModuleLoadError; + +//! Returns an Error object for any argument it receives. If the +//! argument already is an Error object or is empty, it does nothing. +object mkerror(mixed error) +{ + if (error == UNDEFINED) + return error; + if (objectp(error) && error->is_generic_error) + return error; + if (arrayp(error)) + return Error.Generic(@error); + if (stringp(error)) + return Error.Generic(error); + return Error.Generic(sprintf("%O", error)); +}
\ No newline at end of file diff --git a/tests/examplefiles/Errors.scala b/tests/examplefiles/Errors.scala index 67198c05..7af70280 100644 --- a/tests/examplefiles/Errors.scala +++ b/tests/examplefiles/Errors.scala @@ -11,6 +11,11 @@ String val foo_+ = "foo plus" val foo_⌬⌬ = "double benzene" + // Test some interpolated strings + val mu = s"${if (true) "a:b" else "c" {with "braces"}}" + val mu2 = f"${if (true) "a:b" else "c" {with "braces"}}" + val raw = raw"a raw\nstring\"with escaped quotes" + def main(argv: Array[String]) { println(⌘.interface + " " + foo_+ + " " + foo_⌬⌬ ) } diff --git a/tests/examplefiles/FakeFile.pike b/tests/examplefiles/FakeFile.pike new file mode 100644 index 00000000..48f3ea64 --- /dev/null +++ b/tests/examplefiles/FakeFile.pike @@ -0,0 +1,360 @@ +#pike __REAL_VERSION__ + +//! A string wrapper that pretends to be a @[Stdio.File] object +//! in addition to some features of a @[Stdio.FILE] object. + + +//! This constant can be used to distinguish a FakeFile object +//! from a real @[Stdio.File] object. +constant is_fake_file = 1; + +protected string data; +protected int ptr; +protected int(0..1) r; +protected int(0..1) w; +protected int mtime; + +protected function read_cb; +protected function read_oob_cb; +protected function write_cb; +protected function write_oob_cb; +protected function close_cb; + +//! @seealso +//! @[Stdio.File()->close()] +int close(void|string direction) { + direction = lower_case(direction||"rw"); + int cr = has_value(direction, "r"); + int cw = has_value(direction, "w"); + + if(cr) { + r = 0; + } + + if(cw) { + w = 0; + } + + // FIXME: Close callback + return 1; +} + +//! @decl void create(string data, void|string type, void|int pointer) +//! @seealso +//! @[Stdio.File()->create()] +void create(string _data, void|string type, int|void _ptr) { + if(!_data) error("No data string given to FakeFile.\n"); + data = _data; + ptr = _ptr; + mtime = time(); + if(type) { + type = lower_case(type); + if(has_value(type, "r")) + r = 1; + if(has_value(type, "w")) + w = 1; + } + else + r = w = 1; +} + +protected string make_type_str() { + string type = ""; + if(r) type += "r"; + if(w) type += "w"; + return type; +} + +//! @seealso +//! @[Stdio.File()->dup()] +this_program dup() { + return this_program(data, make_type_str(), ptr); +} + +//! Always returns 0. +//! @seealso +//! @[Stdio.File()->errno()] +int errno() { return 0; } + +//! Returns size and the creation time of the string. +Stdio.Stat stat() { + Stdio.Stat st = Stdio.Stat(); + st->size = sizeof(data); + st->mtime=st->ctime=mtime; + st->atime=time(); + return st; +} + +//! @seealso +//! @[Stdio.File()->line_iterator()] +String.SplitIterator line_iterator(int|void trim) { + if(trim) + return String.SplitIterator( data-"\r", '\n' ); + return String.SplitIterator( data, '\n' ); +} + +protected mixed id; + +//! @seealso +//! @[Stdio.File()->query_id()] +mixed query_id() { return id; } + +//! @seealso +//! @[Stdio.File()->set_id()] +void set_id(mixed _id) { id = _id; } + +//! @seealso +//! @[Stdio.File()->read_function()] +function(:string) read_function(int nbytes) { + return lambda() { return read(nbytes); }; +} + +//! @seealso +//! @[Stdio.File()->peek()] +int(-1..1) peek(int|float|void timeout) { + if(!r) return -1; + if(ptr >= sizeof(data)) return 0; + return 1; +} + +//! Always returns 0. +//! @seealso +//! @[Stdio.File()->query_address()] +string query_address(void|int(0..1) is_local) { return 0; } + +//! @seealso +//! @[Stdio.File()->read()] +string read(void|int(0..) len, void|int(0..1) not_all) { + if(!r) return 0; + if (len < 0) error("Cannot read negative number of characters.\n"); + int start=ptr; + ptr += len; + if(zero_type(len) || ptr>sizeof(data)) + ptr = sizeof(data); + + // FIXME: read callback + return data[start..ptr-1]; +} + +//! @seealso +//! @[Stdio.FILE()->gets()] +string gets() { + if(!r) return 0; + string ret; + sscanf(data,"%*"+(string)ptr+"s%[^\n]",ret); + if(ret) + { + ptr+=sizeof(ret)+1; + if(ptr>sizeof(data)) + { + ptr=sizeof(data); + if(!sizeof(ret)) + ret = 0; + } + } + + // FIXME: read callback + return ret; +} + +//! @seealso +//! @[Stdio.FILE()->getchar()] +int getchar() { + if(!r) return 0; + int c; + if(catch(c=data[ptr])) + c=-1; + else + ptr++; + + // FIXME: read callback + return c; +} + +//! @seealso +//! @[Stdio.FILE()->unread()] +void unread(string s) { + if(!r) return; + if(data[ptr-sizeof(s)..ptr-1]==s) + ptr-=sizeof(s); + else + { + data=s+data[ptr..]; + ptr=0; + } +} + +//! @seealso +//! @[Stdio.File()->seek()] +int seek(int pos, void|int mult, void|int add) { + if(mult) + pos = pos*mult+add; + if(pos<0) + { + pos = sizeof(data)+pos; + if( pos < 0 ) + pos = 0; + } + ptr = pos; + if( ptr > strlen( data ) ) + ptr = strlen(data); + return ptr; +} + +//! Always returns 1. +//! @seealso +//! @[Stdio.File()->sync()] +int(1..1) sync() { return 1; } + +//! @seealso +//! @[Stdio.File()->tell()] +int tell() { return ptr; } + +//! @seealso +//! @[Stdio.File()->truncate()] +int(0..1) truncate(int length) { + data = data[..length-1]; + return sizeof(data)==length; +} + +//! @seealso +//! @[Stdio.File()->write()] +int(-1..) write(string|array(string) str, mixed ... extra) { + if(!w) return -1; + if(arrayp(str)) str=str*""; + if(sizeof(extra)) str=sprintf(str, @extra); + + if(ptr==sizeof(data)) { + data += str; + ptr = sizeof(data); + } + else if(sizeof(str)==1) + data[ptr++] = str[0]; + else { + data = data[..ptr-1] + str + data[ptr+sizeof(str)..]; + ptr += sizeof(str); + } + + // FIXME: write callback + return sizeof(str); +} + +//! @seealso +//! @[Stdio.File()->set_blocking] +void set_blocking() { + close_cb = 0; + read_cb = 0; + read_oob_cb = 0; + write_cb = 0; + write_oob_cb = 0; +} + +//! @seealso +//! @[Stdio.File()->set_blocking_keep_callbacks] +void set_blocking_keep_callbacks() { } + +//! @seealso +//! @[Stdio.File()->set_blocking] +void set_nonblocking(function rcb, function wcb, function ccb, + function rocb, function wocb) { + read_cb = rcb; + write_cb = wcb; + close_cb = ccb; + read_oob_cb = rocb; + write_oob_cb = wocb; +} + +//! @seealso +//! @[Stdio.File()->set_blocking_keep_callbacks] +void set_nonblocking_keep_callbacks() { } + + +//! @seealso +//! @[Stdio.File()->set_close_callback] +void set_close_callback(function cb) { close_cb = cb; } + +//! @seealso +//! @[Stdio.File()->set_read_callback] +void set_read_callback(function cb) { read_cb = cb; } + +//! @seealso +//! @[Stdio.File()->set_read_oob_callback] +void set_read_oob_callback(function cb) { read_oob_cb = cb; } + +//! @seealso +//! @[Stdio.File()->set_write_callback] +void set_write_callback(function cb) { write_cb = cb; } + +//! @seealso +//! @[Stdio.File()->set_write_oob_callback] +void set_write_oob_callback(function cb) { write_oob_cb = cb; } + + +//! @seealso +//! @[Stdio.File()->query_close_callback] +function query_close_callback() { return close_cb; } + +//! @seealso +//! @[Stdio.File()->query_read_callback] +function query_read_callback() { return read_cb; } + +//! @seealso +//! @[Stdio.File()->query_read_oob_callback] +function query_read_oob_callback() { return read_oob_cb; } + +//! @seealso +//! @[Stdio.File()->query_write_callback] +function query_write_callback() { return write_cb; } + +//! @seealso +//! @[Stdio.File()->query_write_oob_callback] +function query_write_oob_callback() { return write_oob_cb; } + +string _sprintf(int t) { + return t=='O' && sprintf("%O(%d,%O)", this_program, sizeof(data), + make_type_str()); +} + + +// FakeFile specials. + +//! A FakeFile can be casted to a string. +mixed cast(string to) { + switch(to) { + case "string": return data; + case "object": return this; + } + error("Can not cast object to %O.\n", to); +} + +//! Sizeof on a FakeFile returns the size of its contents. +int(0..) _sizeof() { + return sizeof(data); +} + +//! @ignore + +#define NOPE(X) mixed X (mixed ... args) { error("This is a FakeFile. %s is not available.\n", #X); } +NOPE(assign); +NOPE(async_connect); +NOPE(connect); +NOPE(connect_unix); +NOPE(open); +NOPE(open_socket); +NOPE(pipe); +NOPE(tcgetattr); +NOPE(tcsetattr); + +// Stdio.Fd +NOPE(dup2); +NOPE(lock); // We could implement this +NOPE(mode); // We could implement this +NOPE(proxy); // We could implement this +NOPE(query_fd); +NOPE(read_oob); +NOPE(set_close_on_exec); +NOPE(set_keepalive); +NOPE(trylock); // We could implement this +NOPE(write_oob); + +//! @endignore
\ No newline at end of file diff --git a/tests/examplefiles/all.nit b/tests/examplefiles/all.nit new file mode 100644 index 00000000..d4e1ddfa --- /dev/null +++ b/tests/examplefiles/all.nit @@ -0,0 +1,1986 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import gtk + +class CalculatorContext + var result : nullable Float = null + + var last_op : nullable Char = null + + var current : nullable Float = null + var after_point : nullable Int = null + + fun push_op( op : Char ) + do + apply_last_op_if_any + if op == 'C' then + self.result = 0.0 + last_op = null + else + last_op = op # store for next push_op + end + + # prepare next current + after_point = null + current = null + end + + fun push_digit( digit : Int ) + do + var current = current + if current == null then current = 0.0 + + var after_point = after_point + if after_point == null then + current = current * 10.0 + digit.to_f + else + current = current + digit.to_f * 10.0.pow(after_point.to_f) + self.after_point -= 1 + end + + self.current = current + end + + fun switch_to_decimals + do + if self.current == null then current = 0.0 + if after_point != null then return + + after_point = -1 + end + + fun apply_last_op_if_any + do + var op = last_op + + var result = result + if result == null then result = 0.0 + + var current = current + if current == null then current = 0.0 + + if op == null then + result = current + else if op == '+' then + result = result + current + else if op == '-' then + result = result - current + else if op == '/' then + result = result / current + else if op == '*' then + result = result * current + end + self.result = result + self.current = null + end +end + +class CalculatorGui + super GtkCallable + + var win : GtkWindow + var container : GtkGrid + + var lbl_disp : GtkLabel + var but_eq : GtkButton + var but_dot : GtkButton + + var context = new CalculatorContext + + redef fun signal( sender, user_data ) + do + var after_point = context.after_point + if after_point == null then + after_point = 0 + else + after_point = (after_point.abs) + end + + if user_data isa Char then # is an operation + var c = user_data + if c == '.' then + but_dot.sensitive= false + context.switch_to_decimals + lbl_disp.text = "{context.current.to_i}." + else + but_dot.sensitive= true + context.push_op( c ) + + var s = context.result.to_precision_native(6) + var index : nullable Int = null + for i in s.length.times do + var chiffre = s.chars[i] + if chiffre == '0' and index == null then + index = i + else if chiffre != '0' then + index = null + end + end + if index != null then + s = s.substring(0, index) + if s.chars[s.length-1] == ',' then s = s.substring(0, s.length-1) + end + lbl_disp.text = s + end + else if user_data isa Int then # is a number + var n = user_data + context.push_digit( n ) + lbl_disp.text = context.current.to_precision_native(after_point) + end + end + + init + do + init_gtk + + win = new GtkWindow( 0 ) + + container = new GtkGrid(5,5,true) + win.add( container ) + + lbl_disp = new GtkLabel( "_" ) + container.attach( lbl_disp, 0, 0, 5, 1 ) + + # digits + for n in [0..9] do + var but = new GtkButton.with_label( n.to_s ) + but.request_size( 64, 64 ) + but.signal_connect( "clicked", self, n ) + if n == 0 then + container.attach( but, 0, 4, 1, 1 ) + else container.attach( but, (n-1)%3, 3-(n-1)/3, 1, 1 ) + end + + # operators + var r = 1 + for op in ['+', '-', '*', '/' ] do + var but = new GtkButton.with_label( op.to_s ) + but.request_size( 64, 64 ) + but.signal_connect( "clicked", self, op ) + container.attach( but, 3, r, 1, 1 ) + r+=1 + end + + # = + but_eq = new GtkButton.with_label( "=" ) + but_eq.request_size( 64, 64 ) + but_eq.signal_connect( "clicked", self, '=' ) + container.attach( but_eq, 4, 3, 1, 2 ) + + # . + but_dot = new GtkButton.with_label( "." ) + but_dot.request_size( 64, 64 ) + but_dot.signal_connect( "clicked", self, '.' ) + container.attach( but_dot, 1, 4, 1, 1 ) + + #C + var but_c = new GtkButton.with_label( "C" ) + but_c.request_size( 64, 64 ) + but_c.signal_connect("clicked", self, 'C') + container.attach( but_c, 2, 4, 1, 1 ) + + win.show_all + end +end + +# context tests +var context = new CalculatorContext +context.push_digit( 1 ) +context.push_digit( 2 ) +context.push_op( '+' ) +context.push_digit( 3 ) +context.push_op( '*' ) +context.push_digit( 2 ) +context.push_op( '=' ) +var r = context.result.to_precision( 2 ) +assert r == "30.00" else print r + +context = new CalculatorContext +context.push_digit( 1 ) +context.push_digit( 4 ) +context.switch_to_decimals +context.push_digit( 1 ) +context.push_op( '*' ) +context.push_digit( 3 ) +context.push_op( '=' ) +r = context.result.to_precision( 2 ) +assert r == "42.30" else print r + +context.push_op( '+' ) +context.push_digit( 1 ) +context.push_digit( 1 ) +context.push_op( '=' ) +r = context.result.to_precision( 2 ) +assert r == "53.30" else print r + +context = new CalculatorContext +context.push_digit( 4 ) +context.push_digit( 2 ) +context.switch_to_decimals +context.push_digit( 3 ) +context.push_op( '/' ) +context.push_digit( 3 ) +context.push_op( '=' ) +r = context.result.to_precision( 2 ) +assert r == "14.10" else print r + +#test multiple decimals +context = new CalculatorContext +context.push_digit( 5 ) +context.push_digit( 0 ) +context.switch_to_decimals +context.push_digit( 1 ) +context.push_digit( 2 ) +context.push_digit( 3 ) +context.push_op( '+' ) +context.push_digit( 1 ) +context.push_op( '=' ) +r = context.result.to_precision( 3 ) +assert r == "51.123" else print r + +#test 'C' button +context = new CalculatorContext +context.push_digit( 1 ) +context.push_digit( 0 ) +context.push_op( '+' ) +context.push_digit( 1 ) +context.push_digit( 0 ) +context.push_op( '=' ) +context.push_op( 'C' ) +r = context.result.to_precision( 1 ) +assert r == "0.0" else print r + +# graphical application + +if "NIT_TESTING".environ != "true" then + var app = new CalculatorGui + run_gtk +end +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2013 Matthieu Lucas <lucasmatthieu@gmail.com> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This sample has been implemented to show you how simple is it to play +# with native callbacks (C) through an high level with NIT program. + +module callback_chimpanze +import callback_monkey + +class Chimpanze + super MonkeyActionCallable + + fun create + do + var monkey = new Monkey + print "Hum, I'm sleeping ..." + # Invoking method which will take some time to compute, and + # will be back in wokeUp method with information. + # - Callback method defined in MonkeyActionCallable Interface + monkey.wokeUpAction(self, "Hey, I'm awake.") + end + + # Inherit callback method, defined by MonkeyActionCallable interface + # - Back of wokeUpAction method + redef fun wokeUp( sender:Monkey, message:Object ) + do + print message + end +end + +var m = new Chimpanze +m.create +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2013 Matthieu Lucas <lucasmatthieu@gmail.com> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This sample has been implemented to show you how simple is it to play +# with native callbacks (C) through an high level with NIT program. + +module callback_monkey + +in "C header" `{ + #include <stdio.h> + #include <stdlib.h> + + typedef struct { + int id; + int age; + } CMonkey; + + typedef struct { + MonkeyActionCallable toCall; + Object message; + } MonkeyAction; +`} + +in "C body" `{ + // Method which reproduce a callback answer + // Please note that a function pointer is only used to reproduce the callback + void cbMonkey(CMonkey *mkey, void callbackFunc(CMonkey*, MonkeyAction*), MonkeyAction *data) + { + sleep(2); + callbackFunc( mkey, data ); + } + + // Back of background treatment, will be redirected to callback function + void nit_monkey_callback_func( CMonkey *mkey, MonkeyAction *data ) + { + // To call a your method, the signature must be written like this : + // <Interface Name>_<Method>... + MonkeyActionCallable_wokeUp( data->toCall, mkey, data->message ); + } +`} + +# Implementable interface to get callback in defined methods +interface MonkeyActionCallable + fun wokeUp( sender:Monkey, message: Object) is abstract +end + +# Defining my object type Monkey, which is, in a low level, a pointer to a C struct (CMonkey) +extern class Monkey `{ CMonkey * `} + + new `{ + CMonkey *monkey = malloc( sizeof(CMonkey) ); + monkey->age = 10; + monkey->id = 1; + return monkey; + `} + + # Object method which will get a callback in wokeUp method, defined in MonkeyActionCallable interface + # Must be defined as Nit/C method because of C call inside + fun wokeUpAction( toCall: MonkeyActionCallable, message: Object ) is extern import MonkeyActionCallable.wokeUp `{ + + // Allocating memory to keep reference of received parameters : + // - Object receiver + // - Message + MonkeyAction *data = malloc( sizeof(MonkeyAction) ); + + // Incrementing reference counter to prevent from releasing + MonkeyActionCallable_incr_ref( toCall ); + Object_incr_ref( message ); + + data->toCall = toCall; + data->message = message; + + // Calling method which reproduce a callback by passing : + // - Receiver + // - Function pointer to object return method + // - Datas + cbMonkey( recv, &nit_monkey_callback_func, data ); + `} +end +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Implementation of circular lists +# This example shows the usage of generics and somewhat a specialisation of collections. +module circular_list + +# Sequences of elements implemented with a double-linked circular list +class CircularList[E] + # Like standard Array or LinkedList, CircularList is a Sequence. + super Sequence[E] + + # The first node of the list if any + # The special case of an empty list is handled by a null node + private var node: nullable CLNode[E] = null + + redef fun iterator do return new CircularListIterator[E](self) + + redef fun first do return self.node.item + + redef fun push(e) + do + var new_node = new CLNode[E](e) + var n = self.node + if n == null then + # the first node + self.node = new_node + else + # not the first one, so attach nodes correctly. + var old_last_node = n.prev + new_node.next = n + new_node.prev = old_last_node + old_last_node.next = new_node + n.prev = new_node + end + end + + redef fun pop + do + var n = self.node + assert n != null + var prev = n.prev + if prev == n then + # the only node + self.node = null + return n.item + end + # not the only one do detach nodes correctly. + var prev_prev = prev.prev + n.prev = prev_prev + prev_prev.next = n + return prev.item + end + + redef fun unshift(e) + do + # Circularity has benefits. + push(e) + self.node = self.node.prev + end + + redef fun shift + do + # Circularity has benefits. + self.node = self.node.next + return self.pop + end + + # Move the first at the last position, the second at the first, etc. + fun rotate + do + var n = self.node + if n == null then return + self.node = n.next + end + + # Sort the list using the Josephus algorithm. + fun josephus(step: Int) + do + var res = new CircularList[E] + while not self.is_empty do + # count 'step' + for i in [1..step[ do self.rotate + # kill + var x = self.shift + res.add(x) + end + self.node = res.node + end +end + +# Nodes of a CircularList +private class CLNode[E] + # The current item + var item: E + + # The next item in the circular list. + # Because of circularity, there is always a next; + # so by default let it be self + var next: CLNode[E] = self + + # The previous item in the circular list. + # Coherence between next and previous nodes has to be maintained by the + # circular list. + var prev: CLNode[E] = self +end + +# An iterator of a CircularList. +private class CircularListIterator[E] + super IndexedIterator[E] + + redef var index: Int + + # The current node pointed. + # Is null if the list is empty. + var node: nullable CLNode[E] + + # The list iterated. + var list: CircularList[E] + + redef fun is_ok + do + # Empty lists are not OK. + # Pointing again the first node is not OK. + return self.node != null and (self.index == 0 or self.node != self.list.node) + end + + redef fun next + do + self.node = self.node.next + self.index += 1 + end + + redef fun item do return self.node.item + + init(list: CircularList[E]) + do + self.node = list.node + self.list = list + self.index = 0 + end +end + +var i = new CircularList[Int] +i.add_all([1, 2, 3, 4, 5, 6, 7]) +print i.first +print i.join(":") + +i.push(8) +print i.shift +print i.pop +i.unshift(0) +print i.join(":") + +i.josephus(3) +print i.join(":") +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This module beef up the clock module by allowing a clock to be comparable. +# It show the usage of class refinement +module clock_more + +import clock + +redef class Clock + # Clock are now comparable + super Comparable + + # Comparaison of a clock make only sense with an other clock + redef type OTHER: Clock + + redef fun <(o) + do + # Note: < is the only abstract method of Comparable. + # All other operators and methods rely on < and ==. + return self.total_minutes < o.total_minutes + end +end + +var c1 = new Clock(8, 12) +var c2 = new Clock(8, 13) +var c3 = new Clock(9, 13) + +print "{c1}<{c2}? {c1<c2}" +print "{c1}<={c2}? {c1<=c2}" +print "{c1}>{c2}? {c1>c2}" +print "{c1}>={c2}? {c1>=c2}" +print "{c1}<=>{c2}? {c1<=>c2}" +print "{c1},{c2}? max={c1.max(c2)} min={c1.min(c2)}" +print "{c1}.is_between({c2}, {c3})? {c1.is_between(c2, c3)}" +print "{c2}.is_between({c1}, {c3})? {c2.is_between(c1, c3)}" + +print "-" + +c1.minutes += 1 + +print "{c1}<{c2}? {c1<c2}" +print "{c1}<={c2}? {c1<=c2}" +print "{c1}>{c2}? {c1>c2}" +print "{c1}>={c2}? {c1>=c2}" +print "{c1}<=>{c2}? {c1<=>c2}" +print "{c1},{c2}? max={c1.max(c2)} min={c1.min(c2)}" +print "{c1}.is_between({c2}, {c3})? {c1.is_between(c2, c3)}" +print "{c2}.is_between({c1}, {c3})? {c2.is_between(c1, c3)}" +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This module provide a simple wall clock. +# It is an example of getters and setters. +# A beefed-up module is available in clock_more +module clock + +# A simple wall clock with 60 minutes and 12 hours. +class Clock + # total number of minutes from 0 to 719 + var total_minutes: Int + # Note: only the read acces is public, the write access is private. + + # number of minutes in the current hour (from 0 to 59) + fun minutes: Int do return self.total_minutes % 60 + + # set the number of minutes in the current hour. + # if m < 0 or m >= 60, the hour will be changed accordinlgy + fun minutes=(m: Int) do self.total_minutes = self.hours * 60 + m + + # number of hours (from 0 to 11) + fun hours: Int do return self.total_minutes / 60 + + # set the number of hours + # the minutes will not be updated + fun hours=(h: Int) do self.total_minutes = h * 60 + minutes + + # the position of the hour arrow in the [0..60[ interval + fun hour_pos: Int do return total_minutes / 12 + + # replace the arrow of hours (from 0 to 59). + # the hours and the minutes will be updated. + fun hour_pos=(h: Int) do self.total_minutes = h * 12 + + redef fun to_s do return "{hours}:{minutes}" + + fun reset(hours, minutes: Int) do self.total_minutes = hours*60 + minutes + + init(hours, minutes: Int) do self.reset(hours, minutes) + + redef fun ==(o) + do + # Note: o is a nullable Object, a type test is required + # Thanks to adaptive typing, there is no downcast + # i.e. the code is safe! + return o isa Clock and self.total_minutes == o.total_minutes + end +end + +var c = new Clock(10,50) +print "It's {c} o'clock." + +c.minutes += 22 +print "Now it's {c} o'clock." + +print "The short arrow in on the {c.hour_pos/5} and the long arrow in on the {c.minutes/5}." + +c.hours -= 2 +print "Now it's {c} o'clock." + +var c2 = new Clock(9, 11) +print "It's {c2} on the second clock." +print "The two clocks are synchronized: {c == c2}." +c2.minutes += 1 +print "It's now {c2} on the second clock." +print "The two clocks are synchronized: {c == c2}." +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2013 Matthieu Lucas <lucasmatthieu@gmail.com> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Sample of the Curl module. +module curl_http + +import curl + +# Small class to represent an Http Fetcher +class MyHttpFetcher + super CurlCallbacks + + var curl: Curl + var our_body: String = "" + + init(curl: Curl) do self.curl = curl + + # Release curl object + fun destroy do self.curl.destroy + + # Header callback + redef fun header_callback(line: String) do + # We keep this callback silent for testing purposes + #if not line.has_prefix("Date:") then print "Header_callback : {line}" + end + + # Body callback + redef fun body_callback(line: String) do self.our_body = "{self.our_body}{line}" + + # Stream callback - Cf : No one is registered + redef fun stream_callback(buffer: String, size: Int, count: Int) do print "Stream_callback : {buffer} - {size} - {count}" +end + + +# Program +if args.length < 2 then + print "Usage: curl_http <method wished [POST, GET, GET_FILE]> <target url>" +else + var curl = new Curl + var url = args[1] + var request = new CurlHTTPRequest(url, curl) + + # HTTP Get Request + if args[0] == "GET" then + request.verbose = false + var getResponse = request.execute + + if getResponse isa CurlResponseSuccess then + print "Status code : {getResponse.status_code}" + print "Body : {getResponse.body_str}" + else if getResponse isa CurlResponseFailed then + print "Error code : {getResponse.error_code}" + print "Error msg : {getResponse.error_msg}" + end + + # HTTP Post Request + else if args[0] == "POST" then + var myHttpFetcher = new MyHttpFetcher(curl) + request.delegate = myHttpFetcher + + var postDatas = new HeaderMap + postDatas["Bugs Bunny"] = "Daffy Duck" + postDatas["Batman"] = "Robin likes special characters @#ùà!è§'(\"é&://,;<>∞~*" + postDatas["Batman"] = "Yes you can set multiple identical keys, but APACHE will consider only once, the last one" + request.datas = postDatas + request.verbose = false + var postResponse = request.execute + + print "Our body from the callback : {myHttpFetcher.our_body}" + + if postResponse isa CurlResponseSuccess then + print "*** Answer ***" + print "Status code : {postResponse.status_code}" + print "Body should be empty, because we decided to manage callbacks : {postResponse.body_str.length}" + else if postResponse isa CurlResponseFailed then + print "Error code : {postResponse.error_code}" + print "Error msg : {postResponse.error_msg}" + end + + # HTTP Get to file Request + else if args[0] == "GET_FILE" then + var headers = new HeaderMap + headers["Accept"] = "Moo" + request.headers = headers + request.verbose = false + var downloadResponse = request.download_to_file(null) + + if downloadResponse isa CurlFileResponseSuccess then + print "*** Answer ***" + print "Status code : {downloadResponse.status_code}" + print "Size downloaded : {downloadResponse.size_download}" + else if downloadResponse isa CurlResponseFailed then + print "Error code : {downloadResponse.error_code}" + print "Error msg : {downloadResponse.error_msg}" + end + # Program logic + else + print "Usage : Method[POST, GET, GET_FILE]" + end +end +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2013 Matthieu Lucas <lucasmatthieu@gmail.com> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Mail sender sample using the Curl module +module curl_mail + +import curl + +var curl = new Curl +var mail_request = new CurlMailRequest(curl) + +# Networks +var response = mail_request.set_outgoing_server("smtps://smtp.example.org:465", "user@example.org", "mypassword") +if response isa CurlResponseFailed then + print "Error code : {response.error_code}" + print "Error msg : {response.error_msg}" +end + +# Headers +mail_request.from = "Billy Bob" +mail_request.to = ["user@example.org"] +mail_request.cc = ["bob@example.org"] +mail_request.bcc = null + +var headers_body = new HeaderMap +headers_body["Content-Type:"] = "text/html; charset=\"UTF-8\"" +headers_body["Content-Transfer-Encoding:"] = "quoted-printable" +mail_request.headers_body = headers_body + +# Content +mail_request.body = "<h1>Here you can write HTML stuff.</h1>" +mail_request.subject = "Hello From My Nit Program" + +# Others +mail_request.verbose = false + +# Send mail +response = mail_request.execute +if response isa CurlResponseFailed then + print "Error code : {response.error_code}" + print "Error msg : {response.error_msg}" +else if response isa CurlMailResponseSuccess then + print "Mail Sent" +else + print "Unknown Curl Response type" +end +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2012-2013 Alexis Laferrière <alexis.laf@xymus.net> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Draws an arithmetic operation to the terminal +module draw_operation + +redef enum Int + fun n_chars: Int `{ + int c; + if ( abs(recv) >= 10 ) + c = 1+(int)log10f( (float)abs(recv) ); + else + c = 1; + if ( recv < 0 ) c ++; + return c; + `} +end + +redef enum Char + fun as_operator(a, b: Int): Int + do + if self == '+' then return a + b + if self == '-' then return a - b + if self == '*' then return a * b + if self == '/' then return a / b + if self == '%' then return a % b + abort + end + + fun override_dispc: Bool + do + return self == '+' or self == '-' or self == '*' or self == '/' or self == '%' + end + + fun lines(s: Int): Array[Line] + do + if self == '+' then + return [new Line(new P(0,s/2),1,0,s), new Line(new P(s/2,1),0,1,s-2)] + else if self == '-' then + return [new Line(new P(0,s/2),1,0,s)] + else if self == '*' then + var lines = new Array[Line] + for y in [1..s-1[ do + lines.add( new Line(new P(1,y), 1,0,s-2) ) + end + return lines + else if self == '/' then + return [new Line(new P(s-1,0), -1,1, s )] + else if self == '%' then + var q4 = s/4 + var lines = [new Line(new P(s-1,0),-1,1,s)] + for l in [0..q4[ do + lines.append([ new Line( new P(0,l), 1,0,q4), new Line( new P(s-1,s-1-l), -1,0,q4) ]) + end + return lines + else if self == '1' then + return [new Line(new P(s/2,0), 0,1,s),new Line(new P(0,s-1),1,0,s), + new Line( new P(s/2,0),-1,1,s/2)] + else if self == '2' then + return [new Line(new P(0,0), 1,0,s),new Line(new P(s-1,0),0,1,s/2), + new Line( new P(0,s-1),1,0,s), new Line( new P(0,s/2), 0,1,s/2), + new Line( new P(0,s/2), 1,0,s)] + else if self == '3' then + return [new Line(new P(0,0), 1,0,s),new Line(new P(s-1,0),0,1,s), + new Line( new P(0,s-1),1,0,s), new Line( new P(0,s/2), 1,0,s)] + else if self == '4' then + return [new Line(new P(s-1,0),0,1,s), new Line( new P(0,0), 0,1,s/2), + new Line( new P(0,s/2), 1,0,s)] + else if self == '5' then + return [new Line(new P(0,0), 1,0,s),new Line(new P(s-1,s/2),0,1,s/2), + new Line( new P(0,s-1),1,0,s), new Line( new P(0,0), 0,1,s/2), + new Line( new P(0,s/2), 1,0,s)] + else if self == '6' then + return [new Line(new P(0,0), 1,0,s),new Line(new P(s-1,s/2),0,1,s/2), + new Line( new P(0,s-1),1,0,s), new Line( new P(0,0), 0,1,s), + new Line( new P(0,s/2), 1,0,s)] + else if self == '7' then + var tl = new P(0,0) + var tr = new P(s-1,0) + return [new Line(tl, 1,0,s), new Line(tr,-1,1,s)] + else if self == '8' then + return [new Line(new P(0,0), 1,0,s),new Line(new P(s-1,0),0,1,s), + new Line( new P(0,s-1),1,0,s), new Line( new P(0,0), 0,1,s), + new Line( new P(0,s/2), 1,0,s)] + else if self == '9' then + return [new Line(new P(0,0), 1,0,s),new Line(new P(s-1,0),0,1,s), + new Line( new P(0,s-1),1,0,s), new Line( new P(0,0), 0,1,s/2), + new Line( new P(0,s/2), 1,0,s)] + else if self == '0' then + return [new Line(new P(0,0), 1,0,s),new Line(new P(s-1,0),0,1,s), + new Line( new P(0,s-1),1,0,s), new Line( new P(0,0), 0,1,s)] + end + return new Array[Line] + end +end + +class P + var x : Int + var y : Int +end + +redef class String + # hack is to support a bug in the evaluation software + fun draw(dispc: Char, size, gap: Int, hack: Bool) + do + var w = size * length +(length-1)*gap + var h = size + var map = new Array[Array[Char]] + for x in [0..w[ do + map[x] = new Array[Char].filled_with( ' ', h ) + end + + var ci = 0 + for c in self.chars do + var local_dispc + if c.override_dispc then + local_dispc = c + else + local_dispc = dispc + end + + var lines = c.lines( size ) + for line in lines do + var x = line.o.x+ci*size + x += ci*gap + var y = line.o.y + for s in [0..line.len[ do + assert map.length > x and map[x].length > y else print "setting {x},{y} as {local_dispc}" + map[x][y] = local_dispc + x += line.step_x + y += line.step_y + end + end + + ci += 1 + end + + if hack then + for c in [0..size[ do + map[c][0] = map[map.length-size+c][0] + map[map.length-size+c][0] = ' ' + end + end + + for y in [0..h[ do + for x in [0..w[ do + printn map[x][y] + end + print "" + end + end +end + +class Line + var o : P + var step_x : Int + var step_y : Int + var len : Int +end + +var a +var b +var op_char +var disp_char +var disp_size +var disp_gap + +if "NIT_TESTING".environ == "true" then + a = 567 + b = 13 + op_char = '*' + disp_char = 'O' + disp_size = 8 + disp_gap = 1 +else + printn "Left operand: " + a = gets.to_i + + printn "Right operand: " + b = gets.to_i + + printn "Operator (+, -, *, /, %): " + op_char = gets.chars[0] + + printn "Char to display: " + disp_char = gets.chars[0] + + printn "Size of text: " + disp_size = gets.to_i + + printn "Space between digits: " + disp_gap = gets.to_i +end + +var result = op_char.as_operator( a, b ) + +var len_a = a.n_chars +var len_b = b.n_chars +var len_res = result.n_chars +var max_len = len_a.max( len_b.max( len_res ) ) + 1 + +# draw first line +var d = max_len - len_a +var line_a = "" +for i in [0..d[ do line_a += " " +line_a += a.to_s +line_a.draw( disp_char, disp_size, disp_gap, false ) + +print "" +# draw second line +d = max_len - len_b-1 +var line_b = op_char.to_s +for i in [0..d[ do line_b += " " +line_b += b.to_s +line_b.draw( disp_char, disp_size, disp_gap, false ) + +# draw ----- +print "" +for i in [0..disp_size*max_len+(max_len-1)*disp_gap] do + printn "_" +end +print "" +print "" + +# draw result +d = max_len - len_res +var line_res = "" +for i in [0..d[ do line_res += " " +line_res += result.to_s +line_res.draw( disp_char, disp_size, disp_gap, false ) +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Example using the privileges module to drop privileges from root +module drop_privileges + +import privileges + +# basic command line options +var opts = new OptionContext +var opt_ug = new OptionUserAndGroup.for_dropping_privileges +opt_ug.mandatory = true +opts.add_option(opt_ug) + +# parse and check command line options +opts.parse(args) +if not opts.errors.is_empty then + print opts.errors + print "Usage: drop_privileges [options]" + opts.usage + exit 1 +end + +# original user +print "before {sys.uid}:{sys.gid}" + +# make the switch +var user_group = opt_ug.value +assert user_group != null +user_group.drop_privileges + +# final user +print "after {sys.uid}:{sys.egid}" +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2012-2013 Alexis Laferrière <alexis.laf@xymus.net> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This module illustrates some uses of the FFI, specifically +# how to use extern methods. Which means to implement a Nit method in C. +module extern_methods + +redef enum Int + # Returns self'th fibonnaci number + # implemented here in C for optimization purposes + fun fib : Int import fib `{ + if ( recv < 2 ) + return recv; + else + return Int_fib( recv-1 ) + Int_fib( recv-2 ); + `} + + # System call to sleep for "self" seconds + fun sleep `{ + sleep( recv ); + `} + + # Return atan2l( self, x ) from libmath + fun atan_with( x : Int ) : Float `{ + return atan2( recv, x ); + `} + + # This method callback to Nit methods from C code + # It will use from C code: + # * the local fib method + # * the + operator, a method of Int + # * to_s, a method of all objects + # * String.to_cstring, a method of String to return an equivalent char* + fun foo import fib, +, to_s, String.to_cstring `{ + long recv_fib = Int_fib( recv ); + long recv_plus_fib = Int__plus( recv, recv_fib ); + + String nit_string = Int_to_s( recv_plus_fib ); + char *c_string = String_to_cstring( nit_string ); + + printf( "from C: self + fib(self) = %s\n", c_string ); + `} + + # Equivalent to foo but written in pure Nit + fun bar do print "from Nit: self + fib(self) = {self+self.fib}" +end + +print 12.fib + +print "sleeping 1 second..." +1.sleep + +print 100.atan_with( 200 ) +8.foo +8.bar + +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2004-2008 Jean Privat <jean@pryen.org> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# A simple exemple of refinement where a method is added to the integer class. +module fibonacci + +redef class Int + # Calculate the self-th element of the fibonacci sequence. + fun fibonacci: Int + do + if self < 2 then + return 1 + else + return (self-2).fibonacci + (self-1).fibonacci + end + end +end + +# Print usage and exit. +fun usage +do + print "Usage: fibonnaci <integer>" + exit 0 +end + +# Main part +if args.length != 1 then + usage +end +print args.first.to_i.fibonacci +print "hello world" +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import html + +class NitHomepage + super HTMLPage + + redef fun head do + add("meta").attr("charset", "utf-8") + add("title").text("Nit") + add("link").attr("rel", "icon").attr("href", "http://nitlanguage.org/favicon.ico").attr("type", "image/x-icon") + add("link").attr("rel", "stylesheet").attr("href", "http://nitlanguage.org/style.css").attr("type", "text/css") + add("link").attr("rel", "stylesheet").attr("href", "http://nitlanguage.org/local.css").attr("type", "text/css") + end + + redef fun body do + open("article").add_class("page") + open("section").add_class("pageheader") + add_html("<a id='toptitle_first' class='toptitle'>the</a><a id='toptitle_second' class='toptitle' href=''>Nit</a><a id='toptitle_third' class='toptitle' href=''>Programming Language</a>") + open("header").add_class("header") + open("div").add_class("topsubtitle") + add("p").text("A Fun Language for Serious Programming") + close("div") + close("header") + close("section") + + open("div").attr("id", "pagebody") + open("section").attr("id", "content") + add("h1").text("# What is Nit?") + add("p").text("Nit is an object-oriented programming language. The goal of Nit is to propose a robust statically typed programming language where structure is not a pain.") + add("p").text("So, what does the famous hello world program look like, in Nit?") + add_html("<pre><tt><span class='normal'>print </span><span class='string'>'Hello, World!'</span></tt></pre>") + + add("h1").text("# Feature Highlights") + add("h2").text("Usability") + add("p").text("Nit's goal is to be usable by real programmers for real projects") + + open("ul") + open("li") + add("a").attr("href", "http://en.wikipedia.org/wiki/KISS_principle").text("KISS principle") + close("li") + add("li").text("Script-like language without verbosity nor cryptic statements") + add("li").text("Painless static types: static typing should help programmers") + add("li").text("Efficient development, efficient execution, efficient evolution.") + close("ul") + + add("h2").text("Robustness") + add("p").text("Nit will help you to write bug-free programs") + + open("ul") + add("li").text("Strong static typing") + add("li").text("No more NullPointerException") + close("ul") + + add("h2").text("Object-Oriented") + add("p").text("Nit's guideline is to follow the most powerful OO principles") + + open("ul") + open("li") + add("a").attr("href", "./everything_is_an_object/").text("Everything is an object") + close("li") + open("li") + add("a").attr("href", "./multiple_inheritance/").text("Multiple inheritance") + close("li") + open("li") + add("a").attr("href", "./refinement/").text("Open classes") + close("li") + open("li") + add("a").attr("href", "./virtual_types/").text("Virtual types") + close("li") + close("ul") + + + add("h1").text("# Getting Started") + add("p").text("Get Nit from its Git repository:") + + add_html("<pre><code>$ git clone http://nitlanguage.org/nit.git</code></pre>") + add("p").text("Build the compiler (may be long):") + add_html("<pre><code>$ cd nit\n") + add_html("$ make</code></pre>") + add("p").text("Compile a program:") + add_html("<pre><code>$ bin/nitc examples/hello_world.nit</code></pre>") + add("p").text("Execute the program:") + add_html("<pre><code>$ ./hello_world</code></pre>") + close("section") + close("div") + close("article") + end +end + +var page = new NitHomepage +page.write_to stdout +page.write_to_file("nit.html") +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# An example that defines and uses stacks of integers. +# The implementation is done with a simple linked list. +# It features: free constructors, nullable types and some adaptive typing. +module int_stack + +# A stack of integer implemented by a simple linked list. +# Note that this is only a toy class since a real linked list will gain to use +# generics and extends interfaces, like Collection, from the standard library. +class IntStack + # The head node of the list. + # Null means that the stack is empty. + private var head: nullable ISNode = null + + # Add a new integer in the stack. + fun push(val: Int) + do + self.head = new ISNode(val, self.head) + end + + # Remove and return the last pushed integer. + # Return null if the stack is empty. + fun pop: nullable Int + do + var head = self.head + if head == null then return null + # Note: the followings are statically safe because of the + # previous 'if'. + var val = head.val + self.head = head.next + return val + end + + # Return the sum of all integers of the stack. + # Return 0 if the stack is empty. + fun sumall: Int + do + var sum = 0 + var cur = self.head + while cur != null do + # Note: the followings are statically safe because of + # the condition of the 'while'. + sum += cur.val + cur = cur.next + end + return sum + end + + # Note: Because all attributes have a default value, a free constructor + # "init()" is implicitly defined. +end + +# A node of a IntStack +private class ISNode + # The integer value stored in the node. + var val: Int + + # The next node, if any. + var next: nullable ISNode + + # Note: A free constructor "init(val: Int, next: nullable ISNode)" is + # implicitly defined. +end + +var l = new IntStack +l.push(1) +l.push(2) +l.push(3) + +print l.sumall + +# Note: the 'for' control structure cannot be used on IntStack in its current state. +# It requires a more advanced topic. +# However, why not using the 'loop' control structure? +loop + var i = l.pop + if i == null then break + # The following is statically safe because of the previous 'if'. + print i * 10 +end + +# Note: 'or else' is used to give an alternative of a null expression. +l.push(5) +print l.pop or else 0 # l.pop gives 5, so print 5 +print l.pop or else 0 # l.pop gives null, so print the alternative: 0 + + +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Basic example of OpenGL ES 2.0 usage from the book OpenGL ES 2.0 Programming Guide. +# +# Code reference: +# https://code.google.com/p/opengles-book-samples/source/browse/trunk/LinuxX11/Chapter_2/Hello_Triangle/Hello_Triangle.c +module opengles2_hello_triangle + +import glesv2 +import egl +import mnit_linux # for sdl +import x11 + +if "NIT_TESTING".environ == "true" then exit(0) + +var window_width = 800 +var window_height = 600 + +# +## SDL +# +var sdl_display = new SDLDisplay(window_width, window_height) +var sdl_wm_info = new SDLSystemWindowManagerInfo +var x11_window_handle = sdl_wm_info.x11_window_handle + +# +## X11 +# +var x_display = x_open_default_display +assert x_display != 0 else print "x11 fail" + +# +## EGL +# +var egl_display = new EGLDisplay(x_display) +assert egl_display.is_valid else print "EGL display is not valid" +egl_display.initialize + +print "EGL version: {egl_display.version}" +print "EGL vendor: {egl_display.vendor}" +print "EGL extensions: {egl_display.extensions.join(", ")}" +print "EGL client APIs: {egl_display.client_apis.join(", ")}" + +assert egl_display.is_valid else print egl_display.error + +var config_chooser = new EGLConfigChooser +#config_chooser.surface_type_egl +config_chooser.blue_size = 8 +config_chooser.green_size = 8 +config_chooser.red_size = 8 +#config_chooser.alpha_size = 8 +#config_chooser.depth_size = 8 +#config_chooser.stencil_size = 8 +#config_chooser.sample_buffers = 1 +config_chooser.close + +var configs = config_chooser.choose(egl_display) +assert configs != null else print "choosing config failed: {egl_display.error}" +assert not configs.is_empty else print "no EGL config" + +print "{configs.length} EGL configs available" +for config in configs do + var attribs = config.attribs(egl_display) + print "* caveats: {attribs.caveat}" + print " conformant to: {attribs.conformant}" + print " size of RGBA: {attribs.red_size} {attribs.green_size} {attribs.blue_size} {attribs.alpha_size}" + print " buffer, depth, stencil: {attribs.buffer_size} {attribs.depth_size} {attribs.stencil_size}" +end + +var config = configs.first + +var format = config.attribs(egl_display).native_visual_id + +# TODO android part +# Opengles1Display_midway_init(recv, format); + +var surface = egl_display.create_window_surface(config, x11_window_handle, [0]) +assert surface.is_ok else print egl_display.error + +var context = egl_display.create_context(config) +assert context.is_ok else print egl_display.error + +var make_current_res = egl_display.make_current(surface, surface, context) +assert make_current_res + +var width = surface.attribs(egl_display).width +var height = surface.attribs(egl_display).height +print "Width: {width}" +print "Height: {height}" + +assert egl_bind_opengl_es_api else print "eglBingAPI failed: {egl_display.error}" + +# +## GLESv2 +# + +print "Can compile shaders? {gl_shader_compiler}" +assert_no_gl_error + +assert gl_shader_compiler else print "Cannot compile shaders" + +# gl program +print gl_error.to_s +var program = new GLProgram +if not program.is_ok then + print "Program is not ok: {gl_error.to_s}\nLog:" + print program.info_log + abort +end +assert_no_gl_error + +# vertex shader +var vertex_shader = new GLVertexShader +assert vertex_shader.is_ok else print "Vertex shader is not ok: {gl_error}" +vertex_shader.source = """ +attribute vec4 vPosition; +void main() +{ + gl_Position = vPosition; +} """ +vertex_shader.compile +assert vertex_shader.is_compiled else print "Vertex shader compilation failed with: {vertex_shader.info_log} {program.info_log}" +assert_no_gl_error + +# fragment shader +var fragment_shader = new GLFragmentShader +assert fragment_shader.is_ok else print "Fragment shader is not ok: {gl_error}" +fragment_shader.source = """ +precision mediump float; +void main() +{ + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); +} +""" +fragment_shader.compile +assert fragment_shader.is_compiled else print "Fragment shader compilation failed with: {fragment_shader.info_log}" +assert_no_gl_error + +program.attach_shader vertex_shader +program.attach_shader fragment_shader +program.bind_attrib_location(0, "vPosition") +program.link +assert program.is_linked else print "Linking failed: {program.info_log}" +assert_no_gl_error + +# draw! +var vertices = [0.0, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, -0.5, 0.0] +var vertex_array = new VertexArray(0, 3, vertices) +vertex_array.attrib_pointer +gl_clear_color(0.5, 0.0, 0.5, 1.0) +for i in [0..10000[ do + printn "." + assert_no_gl_error + gl_viewport(0, 0, width, height) + gl_clear_color_buffer + program.use + vertex_array.enable + vertex_array.draw_arrays_triangles + egl_display.swap_buffers(surface) +end + +# delete +program.delete +vertex_shader.delete +fragment_shader.delete + +# +## EGL +# +# close +egl_display.make_current(new EGLSurface.none, new EGLSurface.none, new EGLContext.none) +egl_display.destroy_context(context) +egl_display.destroy_surface(surface) + +# +## SDL +# +# close +sdl_display.destroy +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2004-2008 Jean Privat <jean@pryen.org> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# How to print arguments of the command line. +module print_arguments + +for a in args do + print a +end +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2004-2008 Jean Privat <jean@pryen.org> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# A procedural program (without explicit class definition). +# This program manipulates arrays of integers. +module procedural_array + +# The sum of the elements of `a'. +# Uses a 'for' control structure. +fun array_sum(a: Array[Int]): Int +do + var sum = 0 + for i in a do + sum = sum + i + end + return sum +end + +# The sum of the elements of `a' (alternative version). +# Uses a 'while' control structure. +fun array_sum_alt(a: Array[Int]): Int +do + var sum = 0 + var i = 0 + while i < a.length do + sum = sum + a[i] + i = i + 1 + end + return sum +end + +# The main part of the program. +var a = [10, 5, 8, 9] +print(array_sum(a)) +print(array_sum_alt(a)) +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2013 Matthieu Lucas <lucasmatthieu@gmail.com> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Client sample using the Socket module which connect to the server sample. +module socket_client + +import socket + +if args.length < 2 then + print "Usage : socket_client <host> <port>" + return +end + +var s = new Socket.client(args[0], args[1].to_i) +print "[HOST ADDRESS] : {s.address}" +print "[HOST] : {s.host}" +print "[PORT] : {s.port}" +print "Connecting ... {s.connected}" +if s.connected then + print "Writing ... Hello server !" + s.write("Hello server !") + print "[Response from server] : {s.read(100)}" + print "Closing ..." + s.close +end +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2013 Matthieu Lucas <lucasmatthieu@gmail.com> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Server sample using the Socket module which allow client to connect +module socket_server + +import socket + +if args.is_empty then + print "Usage : socket_server <port>" + return +end + +var socket = new Socket.server(args[0].to_i, 1) +print "[PORT] : {socket.port.to_s}" + +var clients = new Array[Socket] +var max = socket +loop + var fs = new SocketObserver(true, true, true) + fs.readset.set(socket) + + for c in clients do fs.readset.set(c) + + if fs.select(max, 4, 0) == 0 then + print "Error occured in select {sys.errno.strerror}" + break + end + + if fs.readset.is_set(socket) then + var ns = socket.accept + print "Accepting {ns.address} ... " + print "[Message from {ns.address}] : {ns.read(100)}" + ns.write("Goodbye client.") + print "Closing {ns.address} ..." + ns.close + end +end + +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import template + +### Here, definition of the specific templates + +# The root template for composers +class TmplComposers + super Template + + # Short list of composers + var composers = new Array[TmplComposer] + + # Detailled list of composers + var composer_details = new Array[TmplComposerDetail] + + # Add a composer in both lists + fun add_composer(firstname, lastname: String, birth, death: Int) + do + composers.add(new TmplComposer(lastname)) + composer_details.add(new TmplComposerDetail(firstname, lastname, birth, death)) + end + + redef fun rendering do + add """ +COMPOSERS +========= +""" + add_all composers + add """ + +DETAILS +======= +""" + add_all composer_details + end +end + +# A composer in the short list of composers +class TmplComposer + super Template + + # Short name + var name: String + + init(name: String) do self.name = name + + redef fun rendering do add "- {name}\n" +end + +# A composer in the detailled list of composers +class TmplComposerDetail + super Template + + var firstname: String + var lastname: String + var birth: Int + var death: Int + + init(firstname, lastname: String, birth, death: Int) do + self.firstname = firstname + self.lastname = lastname + self.birth = birth + self.death = death + end + + redef fun rendering do add """ + +COMPOSER: {{{firstname}}} {{{lastname}}} +BIRTH...: {{{birth}}} +DEATH...: {{{death}}} +""" + +end + +### Here a simple usage of the templates + +var f = new TmplComposers +f.add_composer("Johann Sebastian", "Bach", 1685, 1750) +f.add_composer("George Frideric", "Handel", 1685, 1759) +f.add_composer("Wolfgang Amadeus", "Mozart", 1756, 1791) +f.write_to(stdout) +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2014 Lucas Bajolet <r4pass@hotmail.com> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Sample module for a minimal chat server using Websockets on port 8088 +module websocket_server + +import websocket + +var sock = new WebSocket(8088, 1) + +var msg: String + +if sock.listener.eof then + print sys.errno.strerror +end + +sock.accept + +while not sock.listener.eof do + if not sock.connected then sock.accept + if sys.stdin.poll_in then + msg = gets + printn "Received message : {msg}" + if msg == "exit" then sock.close + if msg == "disconnect" then sock.disconnect_client + sock.write(msg) + end + if sock.can_read(10) then + msg = sock.read_line + if msg != "" then print msg + end +end + diff --git a/tests/examplefiles/ANTLRv3.g b/tests/examplefiles/antlr_ANTLRv3.g index fbe6d654..fbe6d654 100644 --- a/tests/examplefiles/ANTLRv3.g +++ b/tests/examplefiles/antlr_ANTLRv3.g diff --git a/tests/examplefiles/autoit_submit.au3 b/tests/examplefiles/autoit_submit.au3 index e5054dea..84fb7150 100644 --- a/tests/examplefiles/autoit_submit.au3 +++ b/tests/examplefiles/autoit_submit.au3 @@ -16,8 +16,10 @@ _IEFormElementOptionSelect ($oSelect, "S2", 1, "byText") ;options raido
_IEFormElementRadioSelect($oForm, "2nd", "type", 1, "byValue")
+#cs
ConsoleWrite(@Error)
Sleep(10000)
+#ce
_IEFormSubmit($oForm, 0)
_IELoadWait($oIE)
Sleep(60000)
diff --git a/tests/examplefiles/automake.mk b/tests/examplefiles/automake.mk new file mode 100644 index 00000000..47a50a38 --- /dev/null +++ b/tests/examplefiles/automake.mk @@ -0,0 +1,7 @@ +if DEBUG +DBG = debug +else +DBG = +endif +noinst_PROGRAMS = $(DBG) + diff --git a/tests/examplefiles/clojure-weird-keywords.clj b/tests/examplefiles/clojure-weird-keywords.clj new file mode 100644 index 00000000..2d914c59 --- /dev/null +++ b/tests/examplefiles/clojure-weird-keywords.clj @@ -0,0 +1,5 @@ +; Note, clojure lexer is here (and is a good deal more liberal than the language spec: +; https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LispReader.java#L62 + +(defn valid [#^java.lang.reflect.Method meth] + [:keyword :#initial-hash :h#sh-in-middle :hash-at-end# #js {:keyword "value"}]) diff --git a/tests/examplefiles/core.cljs b/tests/examplefiles/core.cljs new file mode 100644 index 00000000..f135b832 --- /dev/null +++ b/tests/examplefiles/core.cljs @@ -0,0 +1,52 @@ + +(ns bounder.core + (:require [bounder.html :as html] + [domina :refer [value set-value! single-node]] + [domina.css :refer [sel]] + [lowline.functions :refer [debounce]] + [enfocus.core :refer [at]] + [cljs.reader :as reader] + [clojure.string :as s]) + (:require-macros [enfocus.macros :as em])) + +(def filter-input + (single-node + (sel ".search input"))) + +(defn project-matches [query project] + (let [words (cons (:name project) + (map name (:categories project))) + to-match (->> words + (s/join "") + (s/lower-case))] + (<= 0 (.indexOf to-match (s/lower-case query))))) + +(defn apply-filter-for [projects] + (let [query (value filter-input)] + (html/render-projects + (filter (partial project-matches query) + projects)))) + +(defn filter-category [projects evt] + (let [target (.-currentTarget evt)] + (set-value! filter-input + (.-innerHTML target)) + (apply-filter-for projects))) + +(defn init-listeners [projects] + (at js/document + ["input"] (em/listen + :keyup + (debounce + (partial apply-filter-for projects) + 500)) + [".category-links li"] (em/listen + :click + (partial filter-category projects)))) + +(defn init [projects-edn] + (let [projects (reader/read-string projects-edn)] + (init-listeners projects) + (html/render-projects projects) + (html/loaded))) + diff --git a/tests/examplefiles/demo.cfm b/tests/examplefiles/demo.cfm index d94a06a0..78098c05 100644 --- a/tests/examplefiles/demo.cfm +++ b/tests/examplefiles/demo.cfm @@ -1,4 +1,11 @@ <!--- cfcomment ---> +<!--- nested <!--- cfcomment ---> ---> +<!--- multi-line +nested +<!--- +cfcomment +---> +---> <!-- html comment --> <html> <head> @@ -17,6 +24,9 @@ #IsDate("foo")#<br /> #DaysInMonth(RightNow)# </cfoutput> +<cfset x="x"> +<cfset y="y"> +<cfset z="z"> <cfoutput group="x"> #x# <cfoutput>#y#</cfoutput> @@ -29,10 +39,12 @@ <cfset greeting = "Hello #person#"> <cfset greeting = "Hello" & " world!"> +<cfset a = 5> +<cfset b = 10> <cfset c = a^b> <cfset c = a MOD b> <cfset c = a / b> <cfset c = a * b> <cfset c = a + b> <cfset c = a - b> - +<!--- <!-- another <!--- nested --> ---> comment ---> diff --git a/tests/examplefiles/demo.css.in b/tests/examplefiles/demo.css.in new file mode 100644 index 00000000..36330a9d --- /dev/null +++ b/tests/examplefiles/demo.css.in @@ -0,0 +1,6 @@ +%if defined(__foo__) +.cls { + color: #fff; +} +%endif +%literal %foo diff --git a/tests/examplefiles/demo.hbs b/tests/examplefiles/demo.hbs new file mode 100644 index 00000000..1b9ed5a7 --- /dev/null +++ b/tests/examplefiles/demo.hbs @@ -0,0 +1,12 @@ +<!-- post.handlebars --> + +<div class='intro'> + {{intro}} +</div> + +{{#if isExpanded}} + <div class='body'>{{body}}</div> + <button {{action contract}}>Contract</button> +{{else}} + <button {{action expand}}>Show More...</button> +{{/if}} diff --git a/tests/examplefiles/demo.js.in b/tests/examplefiles/demo.js.in new file mode 100644 index 00000000..f44fc53d --- /dev/null +++ b/tests/examplefiles/demo.js.in @@ -0,0 +1,6 @@ +window.foo = { +#if defined(__foo__) + 'key': 'value' +#endif +} +#literal #foo diff --git a/tests/examplefiles/demo.xul.in b/tests/examplefiles/demo.xul.in new file mode 100644 index 00000000..9e1f4938 --- /dev/null +++ b/tests/examplefiles/demo.xul.in @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<window + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> +#if defined(__foo__) +<description value="Text" /> +#endif +</window> diff --git a/tests/examplefiles/docker.docker b/tests/examplefiles/docker.docker new file mode 100644 index 00000000..d65385b6 --- /dev/null +++ b/tests/examplefiles/docker.docker @@ -0,0 +1,5 @@ +maintainer First O'Last + +run echo \ + 123 $bar +# comment diff --git a/tests/examplefiles/ember.handlebars b/tests/examplefiles/ember.handlebars new file mode 100644 index 00000000..515dffbd --- /dev/null +++ b/tests/examplefiles/ember.handlebars @@ -0,0 +1,33 @@ +{{#view EmberFirebaseChat.ChatView class="chat-container"}} + <div class="chat-messages-container"> + <ul class="chat-messages"> + {{#each message in content}} + <li> + [{{formatTimestamp "message.timestamp" fmtString="h:mm:ss A"}}] + <strong>{{message.sender}}</strong>: {{message.content}} + </li> + {{/each}} + </ul> + </div> + + {{! Comment }} + {{{unescaped value}}} + + {{#view EmberFirebaseChat.InputView class="chat-input-container"}} + <form class="form-inline"> + {{#if "auth.authed"}} + {{#if "auth.hasName"}} + <input type="text" id="message" placeholder="Message"> + <button {{action "postMessage" target="view"}} class="btn">Send</button> + {{else}} + <input type="text" id="username" placeholder="Enter your username..."> + <button {{action "pickName" target="view"}} class="btn">Send</button> + {{/if}} + {{else}} + <input type="text" placeholder="Log in with Persona to chat!" disabled="disabled"> + <button {{action "login"}} class="btn">Login</button> + {{/if}} + </form> + {{/view}} +{{/view}} + diff --git a/tests/examplefiles/eval.rs b/tests/examplefiles/eval.rs new file mode 100644 index 00000000..17e585a0 --- /dev/null +++ b/tests/examplefiles/eval.rs @@ -0,0 +1,606 @@ +// ------------------------------------------------------------------------------------------------- +// Rick, a Rust intercal compiler. Save your souls! +// +// Copyright (c) 2015 Georg Brandl +// +// This program is free software; you can redistribute it and/or modify it under the terms of the +// GNU General Public License as published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +// even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with this program; +// if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// ------------------------------------------------------------------------------------------------- + +/// Interprets INTERCAL source. +/// +/// The evaluator is used when rick is called with `-i`, or when the compiler generates +/// the output while compiling (in the constant-output case). + +use std::fmt::{ Debug, Display }; +use std::io::Write; +use std::u16; + +use err::{ Res, IE123, IE129, IE252, IE275, IE555, IE633, IE774, IE994 }; +use ast::{ self, Program, Stmt, StmtBody, ComeFrom, Expr, Var, VType }; +use stdops::{ Bind, Array, write_number, read_number, check_chance, check_ovf, pop_jumps, + get_random_seed, mingle, select, and_16, and_32, or_16, or_32, xor_16, xor_32 }; + + +/// Represents a value (either 16-bit or 32-bit) at runtime. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Val { + I16(u16), + I32(u32), +} + +impl Val { + /// Cast as a 16-bit value; returns an error if 32-bit and too big. + pub fn as_u16(&self) -> Res<u16> { + match *self { + Val::I16(v) => Ok(v), + Val::I32(v) => { + if v > (u16::MAX as u32) { + return IE275.err(); + } + Ok(v as u16) + } + } + } + + /// Cast as a 32-bit value; always succeeds. + pub fn as_u32(&self) -> u32 { + match *self { + Val::I16(v) => v as u32, + Val::I32(v) => v + } + } + + /// Cast as an usize value; always succeeds. + pub fn as_usize(&self) -> usize { + self.as_u32() as usize + } + + /// Create from a 32-bit value; will select the smallest possible type. + pub fn from_u32(v: u32) -> Val { + if v & 0xFFFF == v { + Val::I16(v as u16) + } else { + Val::I32(v) + } + } +} + +/// The state of the interpreter's evaluator. +pub struct Eval<'a> { + /// Program to execute. + program: &'a Program, + /// Stream to use for printing output. + stdout: &'a mut Write, + /// Whether to print debugging output during execution. + debug: bool, + /// Variable bindings for the four types of variables. + spot: Vec<Bind<u16>>, + twospot: Vec<Bind<u32>>, + tail: Vec<Bind<Array<u16>>>, + hybrid: Vec<Bind<Array<u32>>>, + /// The infamous NEXT stack, capable of holding 80 elements. + jumps: Vec<ast::LogLine>, + /// Abstain counter for each statement. + abstain: Vec<u32>, + /// Binary I/O "tape" state. + last_in: u8, + last_out: u8, + /// Random number generator state. + rand_st: u32, + /// Counts the number of executed statements. + stmt_ctr: usize, +} + +/// Represents the control flow effect of an executed statement. +enum StmtRes { + /// normal execution, next statement + Next, + /// jump around, from DO ... NEXT + Jump(usize), + /// jump back, from RESUME + Back(usize), + /// start from the first statement, from TRY AGAIN + FromTop, + /// end the program, from GIVE UP + End, +} + +impl<'a> Eval<'a> { + /// Construct a new evaluator. + pub fn new(program: &'a Program, stdout: &'a mut Write, debug: bool, + random: bool) -> Eval<'a> { + let abs = program.stmts.iter().map(|stmt| stmt.props.disabled as u32).collect(); + let nvars = (program.var_info.0.len(), + program.var_info.1.len(), + program.var_info.2.len(), + program.var_info.3.len()); + Eval { + program: program, + stdout: stdout, + debug: debug, + spot: vec![Bind::new(0); nvars.0], + twospot: vec![Bind::new(0); nvars.1], + tail: vec![Bind::new(Array::empty()); nvars.2], + hybrid: vec![Bind::new(Array::empty()); nvars.3], + jumps: Vec::with_capacity(80), + rand_st: if random { get_random_seed() } else { 0 }, + abstain: abs, + last_in: 0, + last_out: 0, + stmt_ctr: 0, + } + } + + /// Interpret the program. Returns either the number of executed statements, + /// or an error (RtError). + pub fn eval(&mut self) -> Res<usize> { + let mut pctr = 0; // index of current statement + let program = self.program.clone(); + let nstmts = program.stmts.len(); + loop { + // check for falling off the end + if pctr >= nstmts { + // if the last statement was a TRY AGAIN, falling off the end is fine + if let StmtBody::TryAgain = program.stmts[program.stmts.len() - 1].body { + break; + } + return IE633.err(); + } + self.stmt_ctr += 1; + let stmt = &program.stmts[pctr]; + // execute statement if not abstained + if self.abstain[pctr] == 0 { + // check execution chance + let (passed, rand_st) = check_chance(stmt.props.chance, self.rand_st); + self.rand_st = rand_st; + if passed { + // try to eval this statement + let res = match self.eval_stmt(stmt) { + // on error, set the correct line number and bubble up + Err(mut err) => { + err.set_line(stmt.props.onthewayto); + // special treatment for NEXT + if let StmtBody::DoNext(n) = stmt.body { + if let Some(i) = program.labels.get(&n) { + err.set_line(program.stmts[*i as usize].props.srcline); + } + } + return Err(err); + } + Ok(res) => res + }; + // handle control flow effects + match res { + StmtRes::Next => { } + StmtRes::Jump(n) => { + self.jumps.push(pctr as u16); // push the line with the NEXT + pctr = n; + continue; // do not increment or check for COME FROMs + } + StmtRes::Back(n) => { + pctr = n; // will be incremented below after COME FROM check + } + StmtRes::FromTop => { + pctr = 0; // start from the beginning, do not push any stack + continue; + } + StmtRes::End => break, + } + } + } + // if we are on the line with the compiler bug, error out + if pctr == self.program.bugline as usize { + return IE774.err_with(None, stmt.props.onthewayto); + } + // try to determine if we have to go to a COME FROM statement + // (note: in general, program.stmts[pctr] != stmt) + // + // the static COME FROM is always a possibility + let mut maybe_next = program.stmts[pctr].comefrom; + // the complicated case: evaluate all computed-come-from expressions + let my_label = program.stmts[pctr].props.label; + if program.uses_complex_comefrom && my_label > 0 { + for (i, stmt) in program.stmts.iter().enumerate() { + if let StmtBody::ComeFrom(ComeFrom::Expr(ref e)) = stmt.body { + let v = try!(try!(self.eval_expr(e)).as_u16()); + if v == my_label { + // as soon as we have multiple candidates, we can bail out + if maybe_next.is_some() { + return IE555.err(); + } + maybe_next = Some(i as u16); + } + } + } + } + // check for COME FROMs from this line + if let Some(next) = maybe_next { + let next = next as usize; + // check for abstained COME FROM + if self.abstain[next] == 0 { + // the COME FROM can also have a % chance + let (passed, rand_st) = check_chance(program.stmts[next].props.chance, + self.rand_st); + self.rand_st = rand_st; + if passed { + pctr = next; + continue; + } + } + } + // no COME FROM, normal execution + pctr += 1; + } + Ok(self.stmt_ctr) + } + + /// Interpret a single statement. + fn eval_stmt(&mut self, stmt: &Stmt) -> Res<StmtRes> { + if self.debug { + println!("\nExecuting Stmt #{} (state before following)", self.stmt_ctr); + self.dump_state(); + println!("{}", stmt); + } + match stmt.body { + StmtBody::Calc(ref var, ref expr) => { + let val = try!(self.eval_expr(expr)); + try!(self.assign(var, val)); + Ok(StmtRes::Next) + } + StmtBody::Dim(ref var, ref exprs) => { + try!(self.array_dim(var, exprs)); + Ok(StmtRes::Next) + } + StmtBody::DoNext(n) => { + match self.program.labels.get(&n) { + // too many jumps on stack already? + Some(_) if self.jumps.len() >= 80 => IE123.err(), + Some(i) => Ok(StmtRes::Jump(*i as usize)), + None => IE129.err(), + } + } + StmtBody::ComeFrom(_) => { + // nothing to do here at runtime + Ok(StmtRes::Next) + } + StmtBody::Resume(ref expr) => { + let n = try!(self.eval_expr(expr)).as_u32(); + // this expect() is safe: if the third arg is true, there will + // be no Ok(None) returns + let next = try!(pop_jumps(&mut self.jumps, n, true, 0)) + .expect("https://xkcd.com/378/ ?!"); + Ok(StmtRes::Back(next as usize)) + } + StmtBody::Forget(ref expr) => { + let n = try!(self.eval_expr(expr)).as_u32(); + try!(pop_jumps(&mut self.jumps, n, false, 0)); + Ok(StmtRes::Next) + } + StmtBody::Ignore(ref vars) => { + for var in vars { + self.set_rw(var, false); + } + Ok(StmtRes::Next) + } + StmtBody::Remember(ref vars) => { + for var in vars { + self.set_rw(var, true); + } + Ok(StmtRes::Next) + } + StmtBody::Stash(ref vars) => { + for var in vars { + self.stash(var); + } + Ok(StmtRes::Next) + } + StmtBody::Retrieve(ref vars) => { + for var in vars { + try!(self.retrieve(var)); + } + Ok(StmtRes::Next) + } + StmtBody::Abstain(ref expr, ref whats) => { + let f: Box<Fn(u32) -> u32> = if let Some(ref e) = *expr { + let n = try!(self.eval_expr(e)).as_u32(); + box move |v: u32| v.saturating_add(n) + } else { + box |_| 1 + }; + for what in whats { + self.abstain(what, &*f); + } + Ok(StmtRes::Next) + } + StmtBody::Reinstate(ref whats) => { + for what in whats { + self.abstain(what, &|v: u32| v.saturating_sub(1)); + } + Ok(StmtRes::Next) + } + StmtBody::ReadOut(ref vars) => { + for var in vars { + match *var { + // read out whole array + Expr::Var(ref var) if var.is_dim() => { + try!(self.array_readout(var)); + } + // read out single var or array element + Expr::Var(ref var) => { + let varval = try!(self.lookup(var)); + try!(write_number(self.stdout, varval.as_u32(), 0)); + } + // read out constant + Expr::Num(_, v) => try!(write_number(self.stdout, v, 0)), + // others will not be generated + _ => return IE994.err(), + }; + } + Ok(StmtRes::Next) + } + StmtBody::WriteIn(ref vars) => { + for var in vars { + if var.is_dim() { + // write in whole array + try!(self.array_writein(var)); + } else { + // write in single var or array element + let n = try!(read_number(0)); + try!(self.assign(var, Val::from_u32(n))); + } + } + Ok(StmtRes::Next) + } + // this one is only generated by the constant-program optimizer + StmtBody::Print(ref s) => { + if let Err(_) = self.stdout.write(&s) { + return IE252.err(); + } + Ok(StmtRes::Next) + } + StmtBody::TryAgain => Ok(StmtRes::FromTop), + StmtBody::GiveUp => Ok(StmtRes::End), + StmtBody::Error(ref e) => Err((*e).clone()), + } + } + + /// Evaluate an expression to a value. + fn eval_expr(&self, expr: &Expr) -> Res<Val> { + match *expr { + Expr::Num(vtype, v) => match vtype { + VType::I16 => Ok(Val::I16(v as u16)), + VType::I32 => Ok(Val::I32(v)), + }, + Expr::Var(ref var) => self.lookup(var), + Expr::Mingle(ref vx, ref wx) => { + let v = try!(self.eval_expr(vx)).as_u32(); + let w = try!(self.eval_expr(wx)).as_u32(); + let v = try!(check_ovf(v, 0)); + let w = try!(check_ovf(w, 0)); + Ok(Val::I32(mingle(v, w))) + } + Expr::Select(vtype, ref vx, ref wx) => { + let v = try!(self.eval_expr(vx)); + let w = try!(self.eval_expr(wx)); + if vtype == VType::I16 { + Ok(Val::I16(select(v.as_u32(), try!(w.as_u16()) as u32) as u16)) + } else { + Ok(Val::I32(select(v.as_u32(), w.as_u32()))) + } + } + Expr::And(vtype, ref vx) => { + let v = try!(self.eval_expr(vx)); + match vtype { + VType::I16 => Ok(Val::I16(and_16(try!(v.as_u16()) as u32) as u16)), + VType::I32 => Ok(Val::I32(and_32(v.as_u32()))), + } + } + Expr::Or(vtype, ref vx) => { + let v = try!(self.eval_expr(vx)); + match vtype { + VType::I16 => Ok(Val::I16(or_16(try!(v.as_u16()) as u32) as u16)), + VType::I32 => Ok(Val::I32(or_32(v.as_u32()))), + } + } + Expr::Xor(vtype, ref vx) => { + let v = try!(self.eval_expr(vx)); + match vtype { + VType::I16 => Ok(Val::I16(xor_16(try!(v.as_u16()) as u32) as u16)), + VType::I32 => Ok(Val::I32(xor_32(v.as_u32()))), + } + } + Expr::RsNot(ref vx) => { + let v = try!(self.eval_expr(vx)); + Ok(Val::I32(!v.as_u32())) + } + Expr::RsAnd(ref vx, ref wx) => { + let v = try!(self.eval_expr(vx)); + let w = try!(self.eval_expr(wx)); + Ok(Val::I32(v.as_u32() & w.as_u32())) + } + Expr::RsOr(ref vx, ref wx) => { + let v = try!(self.eval_expr(vx)); + let w = try!(self.eval_expr(wx)); + Ok(Val::I32(v.as_u32() | w.as_u32())) + } + Expr::RsXor(ref vx, ref wx) => { + let v = try!(self.eval_expr(vx)); + let w = try!(self.eval_expr(wx)); + Ok(Val::I32(v.as_u32() ^ w.as_u32())) + } + Expr::RsRshift(ref vx, ref wx) => { + let v = try!(self.eval_expr(vx)); + let w = try!(self.eval_expr(wx)); + Ok(Val::I32(v.as_u32() >> w.as_u32())) + } + Expr::RsLshift(ref vx, ref wx) => { + let v = try!(self.eval_expr(vx)); + let w = try!(self.eval_expr(wx)); + Ok(Val::I32(v.as_u32() << w.as_u32())) + } + // Expr::RsEqual(ref vx, ref wx) => { + // let v = try!(self.eval_expr(vx)); + // let w = try!(self.eval_expr(wx)); + // Ok(Val::I32((v.as_u32() == w.as_u32()) as u32)) + // } + Expr::RsNotEqual(ref vx, ref wx) => { + let v = try!(self.eval_expr(vx)); + let w = try!(self.eval_expr(wx)); + Ok(Val::I32((v.as_u32() != w.as_u32()) as u32)) + } + Expr::RsPlus(ref vx, ref wx) => { + let v = try!(self.eval_expr(vx)); + let w = try!(self.eval_expr(wx)); + Ok(Val::I32(v.as_u32() + w.as_u32())) + } + Expr::RsMinus(ref vx, ref wx) => { + let v = try!(self.eval_expr(vx)); + let w = try!(self.eval_expr(wx)); + Ok(Val::I32(v.as_u32() - w.as_u32())) + } + } + } + + #[inline] + fn eval_subs(&self, subs: &Vec<Expr>) -> Res<Vec<usize>> { + subs.iter().map(|v| self.eval_expr(v).map(|w| w.as_usize())).collect() + } + + /// Dimension an array. + fn array_dim(&mut self, var: &Var, dims: &Vec<Expr>) -> Res<()> { + let dims = try!(self.eval_subs(dims)); + match *var { + Var::A16(n, _) => self.tail[n].dimension(dims, 0), + Var::A32(n, _) => self.hybrid[n].dimension(dims, 0), + _ => return IE994.err(), + } + } + + /// Assign to a variable. + fn assign(&mut self, var: &Var, val: Val) -> Res<()> { + match *var { + Var::I16(n) => Ok(self.spot[n].assign(try!(val.as_u16()))), + Var::I32(n) => Ok(self.twospot[n].assign(val.as_u32())), + Var::A16(n, ref subs) => { + let subs = try!(self.eval_subs(subs)); + self.tail[n].set_md(subs, try!(val.as_u16()), 0) + } + Var::A32(n, ref subs) => { + let subs = try!(self.eval_subs(subs)); + self.hybrid[n].set_md(subs, val.as_u32(), 0) + } + } + } + + /// Look up the value of a variable. + fn lookup(&self, var: &Var) -> Res<Val> { + match *var { + Var::I16(n) => Ok(Val::I16(self.spot[n].val)), + Var::I32(n) => Ok(Val::I32(self.twospot[n].val)), + Var::A16(n, ref subs) => { + let subs = try!(self.eval_subs(subs)); + self.tail[n].get_md(subs, 0).map(Val::I16) + } + Var::A32(n, ref subs) => { + let subs = try!(self.eval_subs(subs)); + self.hybrid[n].get_md(subs, 0).map(Val::I32) + } + } + } + + /// Process a STASH statement. + fn stash(&mut self, var: &Var) { + match *var { + Var::I16(n) => self.spot[n].stash(), + Var::I32(n) => self.twospot[n].stash(), + Var::A16(n, _) => self.tail[n].stash(), + Var::A32(n, _) => self.hybrid[n].stash(), + } + } + + /// Process a RETRIEVE statement. + fn retrieve(&mut self, var: &Var) -> Res<()> { + match *var { + Var::I16(n) => self.spot[n].retrieve(0), + Var::I32(n) => self.twospot[n].retrieve(0), + Var::A16(n, _) => self.tail[n].retrieve(0), + Var::A32(n, _) => self.hybrid[n].retrieve(0), + } + } + + /// Process an IGNORE or REMEMBER statement. Cannot fail. + fn set_rw(&mut self, var: &Var, rw: bool) { + match *var { + Var::I16(n) => self.spot[n].rw = rw, + Var::I32(n) => self.twospot[n].rw = rw, + Var::A16(n, _) => self.tail[n].rw = rw, + Var::A32(n, _) => self.hybrid[n].rw = rw, + } + } + + /// P()rocess an ABSTAIN or REINSTATE statement. Cannot fail. + fn abstain(&mut self, what: &ast::Abstain, f: &Fn(u32) -> u32) { + if let &ast::Abstain::Label(lbl) = what { + let idx = self.program.labels[&lbl] as usize; + if self.program.stmts[idx].body != StmtBody::GiveUp { + self.abstain[idx] = f(self.abstain[idx]); + } + } else { + for (i, stype) in self.program.stmt_types.iter().enumerate() { + if stype == what { + self.abstain[i] = f(self.abstain[i]); + } + } + } + } + + /// Array readout helper. + fn array_readout(&mut self, var: &Var) -> Res<()> { + let state = &mut self.last_out; + match *var { + Var::A16(n, _) => self.tail[n].readout(self.stdout, state, 0), + Var::A32(n, _) => self.hybrid[n].readout(self.stdout, state, 0), + _ => return IE994.err(), + } + } + + /// Array writein helper. + fn array_writein(&mut self, var: &Var) -> Res<()> { + let state = &mut self.last_in; + match *var { + Var::A16(n, _) => self.tail[n].writein(state, 0), + Var::A32(n, _) => self.hybrid[n].writein(state, 0), + _ => return IE994.err(), + } + } + + /// Debug helpers. + fn dump_state(&self) { + self.dump_state_one(&self.spot, "."); + self.dump_state_one(&self.twospot, ":"); + self.dump_state_one(&self.tail, ","); + self.dump_state_one(&self.hybrid, ";"); + if self.jumps.len() > 0 { + println!("Next stack: {:?}", self.jumps); + } + //println!("Abstained: {:?}", self.abstain); + } + + fn dump_state_one<T: Debug + Display>(&self, vec: &Vec<Bind<T>>, sigil: &str) { + if vec.len() > 0 { + for (i, v) in vec.iter().enumerate() { + print!("{}{} = {}, ", sigil, i, v); + } + println!(""); + } + } +} diff --git a/tests/examplefiles/example.als b/tests/examplefiles/example.als new file mode 100644 index 00000000..3a5ab82b --- /dev/null +++ b/tests/examplefiles/example.als @@ -0,0 +1,217 @@ +module examples/systems/views + +/* + * Model of views in object-oriented programming. + * + * Two object references, called the view and the backing, + * are related by a view mechanism when changes to the + * backing are automatically propagated to the view. Note + * that the state of a view need not be a projection of the + * state of the backing; the keySet method of Map, for + * example, produces two view relationships, and for the + * one in which the map is modified by changes to the key + * set, the value of the new map cannot be determined from + * the key set. Note that in the iterator view mechanism, + * the iterator is by this definition the backing object, + * since changes are propagated from iterator to collection + * and not vice versa. Oddly, a reference may be a view of + * more than one backing: there can be two iterators on the + * same collection, eg. A reference cannot be a view under + * more than one view type. + * + * A reference is made dirty when it is a backing for a view + * with which it is no longer related by the view invariant. + * This usually happens when a view is modified, either + * directly or via another backing. For example, changing a + * collection directly when it has an iterator invalidates + * it, as does changing the collection through one iterator + * when there are others. + * + * More work is needed if we want to model more closely the + * failure of an iterator when its collection is invalidated. + * + * As a terminological convention, when there are two + * complementary view relationships, we will give them types + * t and t'. For example, KeySetView propagates from map to + * set, and KeySetView' propagates from set to map. + * + * author: Daniel Jackson + */ + +open util/ordering[State] as so +open util/relation as rel + +sig Ref {} +sig Object {} + +-- t->b->v in views when v is view of type t of backing b +-- dirty contains refs that have been invalidated +sig State { + refs: set Ref, + obj: refs -> one Object, + views: ViewType -> refs -> refs, + dirty: set refs +-- , anyviews: Ref -> Ref -- for visualization + } +-- {anyviews = ViewType.views} + +sig Map extends Object { + keys: set Ref, + map: keys -> one Ref + }{all s: State | keys + Ref.map in s.refs} +sig MapRef extends Ref {} +fact {State.obj[MapRef] in Map} + +sig Iterator extends Object { + left, done: set Ref, + lastRef: lone done + }{all s: State | done + left + lastRef in s.refs} +sig IteratorRef extends Ref {} +fact {State.obj[IteratorRef] in Iterator} + +sig Set extends Object { + elts: set Ref + }{all s: State | elts in s.refs} +sig SetRef extends Ref {} +fact {State.obj[SetRef] in Set} + +abstract sig ViewType {} +one sig KeySetView, KeySetView', IteratorView extends ViewType {} +fact ViewTypes { + State.views[KeySetView] in MapRef -> SetRef + State.views[KeySetView'] in SetRef -> MapRef + State.views[IteratorView] in IteratorRef -> SetRef + all s: State | s.views[KeySetView] = ~(s.views[KeySetView']) + } + +/** + * mods is refs modified directly or by view mechanism + * doesn't handle possibility of modifying an object and its view at once? + * should we limit frame conds to non-dirty refs? + */ +pred modifies [pre, post: State, rs: set Ref] { + let vr = pre.views[ViewType], mods = rs.*vr { + all r: pre.refs - mods | pre.obj[r] = post.obj[r] + all b: mods, v: pre.refs, t: ViewType | + b->v in pre.views[t] => viewFrame [t, pre.obj[v], post.obj[v], post.obj[b]] + post.dirty = pre.dirty + + {b: pre.refs | some v: Ref, t: ViewType | + b->v in pre.views[t] && !viewFrame [t, pre.obj[v], post.obj[v], post.obj[b]] + } + } + } + +pred allocates [pre, post: State, rs: set Ref] { + no rs & pre.refs + post.refs = pre.refs + rs + } + +/** + * models frame condition that limits change to view object from v to v' when backing object changes to b' + */ +pred viewFrame [t: ViewType, v, v', b': Object] { + t in KeySetView => v'.elts = dom [b'.map] + t in KeySetView' => b'.elts = dom [v'.map] + t in KeySetView' => (b'.elts) <: (v.map) = (b'.elts) <: (v'.map) + t in IteratorView => v'.elts = b'.left + b'.done + } + +pred MapRef.keySet [pre, post: State, setRefs: SetRef] { + post.obj[setRefs].elts = dom [pre.obj[this].map] + modifies [pre, post, none] + allocates [pre, post, setRefs] + post.views = pre.views + KeySetView->this->setRefs + KeySetView'->setRefs->this + } + +pred MapRef.put [pre, post: State, k, v: Ref] { + post.obj[this].map = pre.obj[this].map ++ k->v + modifies [pre, post, this] + allocates [pre, post, none] + post.views = pre.views + } + +pred SetRef.iterator [pre, post: State, iterRef: IteratorRef] { + let i = post.obj[iterRef] { + i.left = pre.obj[this].elts + no i.done + i.lastRef + } + modifies [pre,post,none] + allocates [pre, post, iterRef] + post.views = pre.views + IteratorView->iterRef->this + } + +pred IteratorRef.remove [pre, post: State] { + let i = pre.obj[this], i' = post.obj[this] { + i'.left = i.left + i'.done = i.done - i.lastRef + no i'.lastRef + } + modifies [pre,post,this] + allocates [pre, post, none] + pre.views = post.views + } + +pred IteratorRef.next [pre, post: State, ref: Ref] { + let i = pre.obj[this], i' = post.obj[this] { + ref in i.left + i'.left = i.left - ref + i'.done = i.done + ref + i'.lastRef = ref + } + modifies [pre, post, this] + allocates [pre, post, none] + pre.views = post.views + } + +pred IteratorRef.hasNext [s: State] { + some s.obj[this].left + } + +assert zippishOK { + all + ks, vs: SetRef, + m: MapRef, + ki, vi: IteratorRef, + k, v: Ref | + let s0=so/first, + s1=so/next[s0], + s2=so/next[s1], + s3=so/next[s2], + s4=so/next[s3], + s5=so/next[s4], + s6=so/next[s5], + s7=so/next[s6] | + ({ + precondition [s0, ks, vs, m] + no s0.dirty + ks.iterator [s0, s1, ki] + vs.iterator [s1, s2, vi] + ki.hasNext [s2] + vi.hasNext [s2] + ki.this/next [s2, s3, k] + vi.this/next [s3, s4, v] + m.put [s4, s5, k, v] + ki.remove [s5, s6] + vi.remove [s6, s7] + } => no State.dirty) + } + +pred precondition [pre: State, ks, vs, m: Ref] { + // all these conditions and other errors discovered in scope of 6 but 8,3 + // in initial state, must have view invariants hold + (all t: ViewType, b, v: pre.refs | + b->v in pre.views[t] => viewFrame [t, pre.obj[v], pre.obj[v], pre.obj[b]]) + // sets are not aliases +-- ks != vs + // sets are not views of map +-- no (ks+vs)->m & ViewType.pre.views + // no iterator currently on either set +-- no Ref->(ks+vs) & ViewType.pre.views + } + +check zippishOK for 6 but 8 State, 3 ViewType expect 1 + +/** + * experiment with controlling heap size + */ +fact {all s: State | #s.obj < 5} diff --git a/tests/examplefiles/example.c b/tests/examplefiles/example.c index a7f546d1..7bf70149 100644 --- a/tests/examplefiles/example.c +++ b/tests/examplefiles/example.c @@ -195,7 +195,7 @@ char convertType(int type) { case TYPE_INT: return 'I'; case TYPE_FLOAT: return 'F'; case TYPE_BOOLEAN: return 'Z'; - default: yyerror("compiler-intern error in convertType().\n"); + default : yyerror("compiler-intern error in convertType().\n"); } return 0; /* to avoid compiler-warning */ } diff --git a/tests/examplefiles/example.chai b/tests/examplefiles/example.chai new file mode 100644 index 00000000..85f53c38 --- /dev/null +++ b/tests/examplefiles/example.chai @@ -0,0 +1,6 @@ +var f = fun(x) { x + 2; } +// comment +puts(someFunc(2 + 2 - 1 * 5 / 4)); +var x = "str"; +def dosomething(lhs, rhs) { print("lhs: ${lhs}, rhs: ${rhs}"); } +callfunc(`+`, 1, 4); diff --git a/tests/examplefiles/example.cob b/tests/examplefiles/example.cob index 3f65e498..92d2e300 100644 --- a/tests/examplefiles/example.cob +++ b/tests/examplefiles/example.cob @@ -2617,940 +2617,4 @@ GC0710 88 Token-Is-Reserved-Word VALUE " ". *****************************************************************
** Perform all program-wide initialization operations **
*****************************************************************
- 101-Establish-Working-Env.
- MOVE TRIM(Src-Filename,Leading) TO Src-Filename
- ACCEPT Env-TEMP
- FROM ENVIRONMENT "TEMP"
- END-ACCEPT
- ACCEPT Lines-Per-Page-ENV
- FROM ENVIRONMENT "OCXREF_LINES"
- END-ACCEPT
- INSPECT Src-Filename REPLACING ALL "\" BY "/"
- INSPECT Env-TEMP REPLACING ALL "\" BY "/"
- MOVE Src-Filename TO Program-Path
- MOVE Program-Path TO Heading-2
- CALL "C$JUSTIFY"
- USING Heading-2, "Right"
- END-CALL
- MOVE LENGTH(TRIM(Src-Filename,Trailing)) TO I
- MOVE 0 TO J
- PERFORM UNTIL Src-Filename(I:1) = '/'
- OR I = 0
- SUBTRACT 1 FROM I
- ADD 1 TO J
- END-PERFORM
- UNSTRING Src-Filename((I + 1):J) DELIMITED BY "."
- INTO Filename, Dummy
- END-UNSTRING
- STRING TRIM(Env-TEMP,Trailing)
- "/"
- TRIM(Filename,Trailing)
- ".i"
- DELIMITED SIZE
- INTO Expanded-Src-Filename
- END-STRING
- STRING Program-Path(1:I)
- TRIM(Filename,Trailing)
- ".lst"
- DELIMITED SIZE
- INTO Report-Filename
- END-STRING
- IF Lines-Per-Page-ENV NOT = SPACES
- MOVE NUMVAL(Lines-Per-Page-ENV) TO Lines-Per-Page
- ELSE
- MOVE 60 TO Lines-Per-Page
- END-IF
- ACCEPT Todays-Date
- FROM DATE YYYYMMDD
- END-ACCEPT
- MOVE Todays-Date TO H1X-Date
- H1S-Date
- MOVE "????????????..." TO SPI-Current-Program-ID
- MOVE SPACES TO SPI-Current-Verb
- Held-Reference
- MOVE "Y" TO F-First-Record
- .
- /
- 200-Execute-cobc SECTION.
- 201-Build-Cmd.
- STRING "cobc -E "
- TRIM(Program-Path, Trailing)
- " > "
- TRIM(Expanded-Src-Filename,Trailing)
- DELIMITED SIZE
- INTO Cmd
- END-STRING
- CALL "SYSTEM"
- USING Cmd
- END-CALL
- IF RETURN-CODE NOT = 0
- DISPLAY
- "Cross-reference terminated by previous errors"
- UPON SYSERR
- END-DISPLAY
- GOBACK
- END-IF
- .
-
- 209-Exit.
- EXIT
- .
- /
- 300-Tokenize-Source SECTION.
- 301-Driver.
- OPEN INPUT Expand-Code
- MOVE SPACES TO Expand-Code-Rec
- MOVE 256 TO Src-Ptr
- MOVE 0 TO Num-UserNames
- SPI-Current-Line-No
- MOVE "?" TO SPI-Current-Division
-GC0710 MOVE "N" TO F-Verb-Has-Been-Found.
- PERFORM FOREVER
- PERFORM 310-Get-Token
- IF Token-Is-EOF
- EXIT PERFORM
- END-IF
- MOVE UPPER-CASE(SPI-Current-Token)
- TO SPI-Current-Token-UC
- IF Token-Is-Verb
- MOVE SPI-Current-Token-UC TO SPI-Current-Verb
- SPI-Prior-Token
- IF Held-Reference NOT = SPACES
- MOVE Held-Reference TO Sort-Rec
- MOVE SPACES TO Held-Reference
- RELEASE Sort-Rec
- END-IF
- END-IF
- EVALUATE TRUE
- WHEN In-IDENTIFICATION-DIVISION
- PERFORM 320-IDENTIFICATION-DIVISION
- WHEN In-ENVIRONMENT-DIVISION
- PERFORM 330-ENVIRONMENT-DIVISION
- WHEN In-DATA-DIVISION
- PERFORM 340-DATA-DIVISION
- WHEN In-PROCEDURE-DIVISION
- PERFORM 350-PROCEDURE-DIVISION
- END-EVALUATE
- IF Token-Is-Key-Word
- MOVE SPI-Current-Token-UC TO SPI-Prior-Token
- END-IF
- IF F-Token-Ended-Sentence = "Y"
- AND SPI-Current-Division NOT = "I"
- MOVE SPACES TO SPI-Prior-Token
- SPI-Current-Verb
- END-IF
-
- END-PERFORM
- CLOSE Expand-Code
- EXIT SECTION
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 310-Get-Token.
- *>-- Position to 1st non-blank character
- MOVE F-Token-Ended-Sentence TO F-Last-Token-Ended-Sent
- MOVE "N" TO F-Token-Ended-Sentence
- PERFORM UNTIL Expand-Code-Rec(Src-Ptr : 1) NOT = SPACE
- IF Src-Ptr > 255
- READ Expand-Code AT END
- IF Held-Reference NOT = SPACES
- MOVE Held-Reference TO Sort-Rec
- MOVE SPACES TO Held-Reference
- RELEASE Sort-Rec
- END-IF
- SET Token-Is-EOF TO TRUE
- MOVE 0 TO SPI-Current-Line-No
- EXIT PARAGRAPH
- END-READ
- IF ECR-1 = "#"
- PERFORM 311-Control-Record
- ELSE
- PERFORM 312-Expand-Code-Record
- END-IF
- ELSE
- ADD 1 TO Src-Ptr
- END-IF
- END-PERFORM
- *>-- Extract token string
- MOVE Expand-Code-Rec(Src-Ptr : 1) TO SPI-Current-Char
- MOVE Expand-Code-Rec(Src-Ptr + 1: 1) TO SPI-Next-Char
- IF SPI-Current-Char = "."
- ADD 1 TO Src-Ptr
- MOVE SPI-Current-Char TO SPI-Current-Token
- MOVE SPACE TO SPI-Token-Type
- MOVE "Y" TO F-Token-Ended-Sentence
- EXIT PARAGRAPH
- END-IF
- IF Current-Char-Is-Punct
- AND SPI-Current-Char = "="
- AND SPI-Current-Division = "P"
- ADD 1 TO Src-Ptr
- MOVE "EQUALS" TO SPI-Current-Token
- MOVE "K" TO SPI-Token-Type
- EXIT PARAGRAPH
- END-IF
- IF Current-Char-Is-Punct *> So subscripts don't get flagged w/ "*"
- AND SPI-Current-Char = "("
- AND SPI-Current-Division = "P"
- MOVE SPACES TO SPI-Prior-Token
- END-IF
- IF Current-Char-Is-Punct
- ADD 1 TO Src-Ptr
- MOVE SPI-Current-Char TO SPI-Current-Token
- MOVE SPACE TO SPI-Token-Type
- EXIT PARAGRAPH
- END-IF
- IF Current-Char-Is-Quote
- ADD 1 TO Src-Ptr
- UNSTRING Expand-Code-Rec
- DELIMITED BY SPI-Current-Char
- INTO SPI-Current-Token
- WITH POINTER Src-Ptr
- END-UNSTRING
- IF Expand-Code-Rec(Src-Ptr : 1) = "."
- MOVE "Y" TO F-Token-Ended-Sentence
- ADD 1 TO Src-Ptr
- END-IF
- SET Token-Is-Literal-Alpha TO TRUE
- EXIT PARAGRAPH
- END-IF
- IF Current-Char-Is-X AND Next-Char-Is-Quote
- ADD 2 TO Src-Ptr
- UNSTRING Expand-Code-Rec
- DELIMITED BY SPI-Next-Char
- INTO SPI-Current-Token
- WITH POINTER Src-Ptr
- END-UNSTRING
- IF Expand-Code-Rec(Src-Ptr : 1) = "."
- MOVE "Y" TO F-Token-Ended-Sentence
- ADD 1 TO Src-Ptr
- END-IF
- SET Token-Is-Literal-Number TO TRUE
- EXIT PARAGRAPH
- END-IF
- IF Current-Char-Is-Z AND Next-Char-Is-Quote
- ADD 2 TO Src-Ptr
- UNSTRING Expand-Code-Rec
- DELIMITED BY SPI-Next-Char
- INTO SPI-Current-Token
- WITH POINTER Src-Ptr
- END-UNSTRING
- IF Expand-Code-Rec(Src-Ptr : 1) = "."
- MOVE "Y" TO F-Token-Ended-Sentence
- ADD 1 TO Src-Ptr
- END-IF
- SET Token-Is-Literal-Alpha TO TRUE
- EXIT PARAGRAPH
- END-IF
- IF F-Processing-PICTURE = "Y"
- UNSTRING Expand-Code-Rec
- DELIMITED BY ". " OR " "
- INTO SPI-Current-Token
- DELIMITER IN Delim
- WITH POINTER Src-Ptr
- END-UNSTRING
- IF Delim = ". "
- MOVE "Y" TO F-Token-Ended-Sentence
- ADD 1 TO Src-Ptr
- END-IF
- IF UPPER-CASE(SPI-Current-Token) = "IS"
- MOVE SPACE TO SPI-Token-Type
- EXIT PARAGRAPH
- ELSE
- MOVE "N" TO F-Processing-PICTURE
- MOVE SPACE TO SPI-Token-Type
- EXIT PARAGRAPH
- END-IF
- END-IF
- UNSTRING Expand-Code-Rec
- DELIMITED BY ". " OR " " OR "=" OR "(" OR ")" OR "*"
- OR "/" OR "&" OR ";" OR "," OR "<"
- OR ">" OR ":"
- INTO SPI-Current-Token
- DELIMITER IN Delim
- WITH POINTER Src-Ptr
- END-UNSTRING
- IF Delim = ". "
- MOVE "Y" TO F-Token-Ended-Sentence
- END-IF
- IF Delim NOT = ". " AND " "
- SUBTRACT 1 FROM Src-Ptr
- END-IF
- *>-- Classify Token
- MOVE UPPER-CASE(SPI-Current-Token) TO Search-Token
- IF Search-Token = "EQUAL" OR "EQUALS"
- MOVE "EQUALS" TO SPI-Current-Token
- MOVE "K" TO SPI-Token-Type
- EXIT PARAGRAPH
- END-IF
- SEARCH ALL Reserved-Word
- WHEN RW-Word (RW-Idx) = Search-Token
- MOVE RW-Type (RW-Idx) TO SPI-Token-Type
-GC0710 IF Token-Is-Verb
-GC0710 MOVE "Y" TO F-Verb-Has-Been-Found
-GC0710 END-IF
- EXIT PARAGRAPH
- END-SEARCH
- *>-- Not a reserved word, must be a user name
- SET Token-Is-Identifier TO TRUE *> NEEDS EXPANSION!!!!
- PERFORM 313-Check-For-Numeric-Token
- IF Token-Is-Literal-Number
- IF (F-Last-Token-Ended-Sent = "Y")
- AND (SPI-Current-Division = "D")
- MOVE "LEVEL #" TO SPI-Current-Token
- MOVE "K" TO SPI-Token-Type
- EXIT PARAGRAPH
- ELSE
- EXIT PARAGRAPH
- END-IF
- END-IF
- EXIT PARAGRAPH
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 311-Control-Record.
- UNSTRING ECR-2-256
- DELIMITED BY '"'
- INTO PIC-X10, PIC-X256, Dummy
- END-UNSTRING
- INSPECT PIC-X10 REPLACING ALL '"' BY SPACE
- COMPUTE I = NUMVAL(PIC-X10) - 1
- IF TRIM(PIC-X256,Trailing) = TRIM(Program-Path,Trailing)
- MOVE I TO SPI-Current-Line-No
- SET In-Main-Module TO TRUE
- IF Saved-Section NOT = SPACES
- MOVE Saved-Section TO SPI-Current-Section
- END-IF
- ELSE
- SET In-Copybook TO TRUE
- IF Saved-Section = SPACES
- MOVE SPI-Current-Section TO Saved-Section
- END-IF
- MOVE LENGTH(TRIM(PIC-X256,Trailing)) TO I
- MOVE 0 TO J
- PERFORM UNTIL PIC-X256(I:1) = '/'
- OR I = 0
- SUBTRACT 1 FROM I
- ADD 1 TO J
- END-PERFORM
- UNSTRING PIC-X256((I + 1):J) DELIMITED BY "."
- INTO Filename, Dummy
- END-UNSTRING
- MOVE "[" TO SPI-CS-1
- MOVE Filename TO SPI-CS-2-14
- IF SPI-CS-11-14 NOT = SPACES
- MOVE "..." TO SPI-CS-11-14
- END-IF
- MOVE "]" TO SPI-CS-15
- END-IF
- MOVE SPACES TO Expand-Code-Rec *> Force another READ
- MOVE 256 TO Src-Ptr
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 312-Expand-Code-Record.
- MOVE 1 TO Src-Ptr
- IF In-Main-Module
- ADD 1 To SPI-Current-Line-No
- END-IF
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 313-Check-For-Numeric-Token.
- MOVE SPI-Current-Token TO PIC-X32
- INSPECT PIC-X32
- REPLACING TRAILING SPACES BY "0"
- IF PIC-X32 IS NUMERIC *> Simple Unsigned Integer
- SET Token-Is-Literal-Number TO TRUE
- EXIT PARAGRAPH
- END-IF
- IF PIC-X32(1:1) = "+" OR "-"
- MOVE "0" TO PIC-X32(1:1)
- END-IF
- MOVE 0 TO Tally
- INSPECT PIC-X32
- TALLYING Tally FOR ALL "."
- IF Tally = 1
- INSPECT PIC-X32 REPLACING ALL "." BY "0"
- END-IF
- IF PIC-X32 IS NUMERIC
- SET Token-Is-Literal-Number TO TRUE
- EXIT PARAGRAPH
- END-IF
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 320-IDENTIFICATION-DIVISION.
-GC0710 MOVE "N" TO F-Verb-Has-Been-Found
- IF Token-Is-Key-Word AND SPI-Current-Token = "DIVISION"
- MOVE SPI-Prior-Token TO SPI-Current-Division
- EXIT PARAGRAPH
- END-IF
- IF SPI-Prior-Token = "PROGRAM-ID"
- MOVE SPACES TO SPI-Prior-Token
- MOVE SPI-Current-Token TO SPI-Current-Program-ID
- IF SPI-CP-13-15 NOT = SPACES
- MOVE "..." TO SPI-CP-13-15
- END-IF
- EXIT PARAGRAPH
- END-IF
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 330-ENVIRONMENT-DIVISION.
- IF Token-Is-Key-Word AND SPI-Current-Token = "DIVISION"
- MOVE SPI-Prior-Token TO SPI-Current-Division
- EXIT PARAGRAPH
- END-IF
- IF Token-Is-Key-Word AND SPI-Current-Token = "SECTION"
- MOVE SPI-Prior-Token TO SPI-Current-Section
- EXIT PARAGRAPH
- END-IF
- IF Token-Is-Identifier
- PERFORM 361-Release-Ref
- END-IF
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 340-DATA-DIVISION.
- IF Token-Is-Key-Word AND SPI-Current-Token = "DIVISION"
- MOVE SPI-Prior-Token TO SPI-Current-Division
- EXIT PARAGRAPH
- END-IF
- IF Token-Is-Key-Word AND SPI-Current-Token = "SECTION"
- MOVE SPI-Prior-Token TO SPI-Current-Section
- EXIT PARAGRAPH
- END-IF
- IF (SPI-Current-Token = "PIC" OR "PICTURE")
- AND (Token-Is-Key-Word)
- MOVE "Y" TO F-Processing-PICTURE
- EXIT PARAGRAPH
- END-IF
-GC0710 IF Token-Is-Reserved-Word
-GC0710 AND SPI-Prior-Token = "LEVEL #"
-GC0710 MOVE SPACES TO SPI-Prior-Token
-GC0710 EXIT PARAGRAPH
-GC0710 END-IF
- IF Token-Is-Identifier
- EVALUATE SPI-Prior-Token
- WHEN "FD"
- PERFORM 360-Release-Def
- MOVE SPACES TO SPI-Prior-Token
- WHEN "SD"
- PERFORM 360-Release-Def
- MOVE SPACES TO SPI-Prior-Token
- WHEN "LEVEL #"
- PERFORM 360-Release-Def
- MOVE SPACES TO SPI-Prior-Token
- WHEN "INDEXED"
- PERFORM 360-Release-Def
- MOVE SPACES TO SPI-Prior-Token
- WHEN "USING"
- PERFORM 362-Release-Upd
- MOVE SPACES TO SPI-Prior-Token
- WHEN "INTO"
- PERFORM 362-Release-Upd
- MOVE SPACES TO SPI-Prior-Token
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- EXIT PARAGRAPH
- END-IF
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 350-PROCEDURE-DIVISION.
- IF SPI-Current-Section NOT = "PROCEDURE"
- MOVE "PROCEDURE" TO SPI-Current-Section
- END-IF
-GC0710 IF SPI-Current-Token-UC = "PROGRAM"
-GC0710 AND SPI-Prior-Token = "END"
-GC0710 MOVE "?" TO SPI-Current-Division
-GC0710 EXIT PARAGRAPH
-GC0710 END-IF
- IF Token-Is-Key-Word AND SPI-Current-Token = "DIVISION"
- MOVE SPI-Prior-Token TO SPI-Current-Division
- EXIT PARAGRAPH
- END-IF
- IF SPI-Current-Verb = SPACES
-GC0710 AND F-Verb-Has-Been-Found = "Y"
- IF Token-Is-Identifier
- PERFORM 360-Release-Def
- MOVE SPACES TO SPI-Prior-Token
- END-IF
- EXIT PARAGRAPH
- END-IF
- IF NOT Token-Is-Identifier
- EXIT PARAGRAPH
- END-IF
- EVALUATE SPI-Current-Verb
- WHEN "ACCEPT"
- PERFORM 351-ACCEPT
- WHEN "ADD"
- PERFORM 351-ADD
- WHEN "ALLOCATE"
- PERFORM 351-ALLOCATE
- WHEN "CALL"
- PERFORM 351-CALL
- WHEN "COMPUTE"
- PERFORM 351-COMPUTE
- WHEN "DIVIDE"
- PERFORM 351-DIVIDE
- WHEN "FREE"
- PERFORM 351-FREE
- WHEN "INITIALIZE"
- PERFORM 351-INITIALIZE
- WHEN "INSPECT"
- PERFORM 351-INSPECT
- WHEN "MOVE"
- PERFORM 351-MOVE
- WHEN "MULTIPLY"
- PERFORM 351-MULTIPLY
- WHEN "PERFORM"
- PERFORM 351-PERFORM
- WHEN "SET"
- PERFORM 351-SET
- WHEN "STRING"
- PERFORM 351-STRING
- WHEN "SUBTRACT"
- PERFORM 351-SUBTRACT
- WHEN "TRANSFORM"
- PERFORM 351-TRANSFORM
- WHEN "UNSTRING"
- PERFORM 351-UNSTRING
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-ACCEPT.
- EVALUATE SPI-Prior-Token
- WHEN "ACCEPT"
- PERFORM 362-Release-Upd
- MOVE SPACES TO SPI-Prior-Token
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-ADD.
- EVALUATE SPI-Prior-Token
- WHEN "GIVING"
- PERFORM 362-Release-Upd
- WHEN "TO"
- PERFORM 362-Release-Upd
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-ALLOCATE.
- EVALUATE SPI-Prior-Token
- WHEN "ALLOCATE"
- PERFORM 362-Release-Upd
- MOVE SPACES TO SPI-Prior-Token
- WHEN "RETURNING"
- PERFORM 362-Release-Upd
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-CALL.
- EVALUATE SPI-Prior-Token
- WHEN "RETURNING"
- PERFORM 362-Release-Upd
- WHEN "GIVING"
- PERFORM 362-Release-Upd
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-COMPUTE.
- EVALUATE SPI-Prior-Token
- WHEN "COMPUTE"
- PERFORM 362-Release-Upd
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-DIVIDE.
- EVALUATE SPI-Prior-Token
- WHEN "INTO"
- PERFORM 363-Set-Upd
- MOVE Sort-Rec TO Held-Reference
- WHEN "GIVING"
- IF Held-Reference NOT = SPACES
- MOVE Held-Reference To Sort-Rec
- MOVE SPACES To Held-Reference
- SR-Ref-Flag
- RELEASE Sort-Rec
- END-IF
- PERFORM 362-Release-Upd
- WHEN "REMAINDER"
- PERFORM 362-Release-Upd
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-FREE.
- PERFORM 362-Release-Upd
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-INITIALIZE.
- EVALUATE SPI-Prior-Token
- WHEN "INITIALIZE"
- PERFORM 362-Release-Upd
- WHEN "REPLACING"
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-INSPECT.
- EVALUATE SPI-Prior-Token
- WHEN "INSPECT"
- PERFORM 364-Set-Ref
- MOVE SPACES TO Held-Reference
- MOVE SPACES TO SPI-Prior-Token
- WHEN "TALLYING"
- PERFORM 362-Release-Upd
- MOVE SPACES TO SPI-Prior-Token
- WHEN "REPLACING"
- IF Held-Reference NOT = SPACES
- MOVE Held-Reference TO Sort-Rec
- MOVE SPACES TO Held-Reference
- MOVE "*" TO SR-Ref-Flag
- RELEASE Sort-Rec
- END-IF
- MOVE SPACES TO SPI-Prior-Token
- WHEN "CONVERTING"
- IF Held-Reference NOT = SPACES
- MOVE Held-Reference TO Sort-Rec
- MOVE SPACES TO Held-Reference
- MOVE "*" TO SR-Ref-Flag
- RELEASE Sort-Rec
- END-IF
- MOVE SPACES TO SPI-Prior-Token
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-MOVE.
- EVALUATE SPI-Prior-Token
- WHEN "TO"
- PERFORM 362-Release-Upd
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-MULTIPLY.
- EVALUATE SPI-Prior-Token
- WHEN "BY"
- PERFORM 363-Set-Upd
- MOVE Sort-Rec TO Held-Reference
- WHEN "GIVING"
- MOVE Held-Reference TO Sort-Rec
- MOVE SPACES TO Held-Reference
- SR-Ref-Flag
- RELEASE Sort-Rec
- PERFORM 362-Release-Upd
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-PERFORM.
- EVALUATE SPI-Prior-Token
- WHEN "VARYING"
- PERFORM 362-Release-Upd
- MOVE SPACES TO SPI-Prior-Token
- WHEN "AFTER"
- PERFORM 362-Release-Upd
- MOVE SPACES TO SPI-Prior-Token
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-SET.
- EVALUATE SPI-Prior-Token
- WHEN "SET"
- PERFORM 362-Release-Upd
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-STRING.
- EVALUATE SPI-Prior-Token
- WHEN "INTO"
- PERFORM 362-Release-Upd
- WHEN "POINTER"
- PERFORM 362-Release-Upd
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-SUBTRACT.
- EVALUATE SPI-Prior-Token
- WHEN "GIVING"
- PERFORM 362-Release-Upd
- WHEN "FROM"
- PERFORM 362-Release-Upd
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-TRANSFORM.
- EVALUATE SPI-Prior-Token
- WHEN "TRANSFORM"
- PERFORM 362-Release-Upd
- MOVE SPACES TO SPI-Prior-Token
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 351-UNSTRING.
- EVALUATE SPI-Prior-Token
- WHEN "INTO"
- PERFORM 362-Release-Upd
- WHEN "DELIMITER"
- PERFORM 362-Release-Upd
- WHEN "COUNT"
- PERFORM 362-Release-Upd
- WHEN "POINTER"
- PERFORM 362-Release-Upd
- WHEN "TALLYING"
- PERFORM 362-Release-Upd
- WHEN OTHER
- PERFORM 361-Release-Ref
- END-EVALUATE
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 360-Release-Def.
- MOVE SPACES TO Sort-Rec
- MOVE SPI-Current-Program-ID TO SR-Prog-ID
- MOVE SPI-Current-Token-UC TO SR-Token-UC
- MOVE SPI-Current-Token TO SR-Token
- MOVE SPI-Current-Section TO SR-Section
- MOVE SPI-Current-Line-No TO SR-Line-No-Def
- MOVE 0 TO SR-Line-No-Ref
- RELEASE Sort-Rec
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 361-Release-Ref.
- PERFORM 364-Set-Ref
- RELEASE Sort-Rec
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 362-Release-Upd.
- PERFORM 363-Set-Upd
- RELEASE Sort-Rec
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 363-Set-Upd.
- MOVE SPACES TO Sort-Rec
- MOVE SPI-Current-Program-ID TO SR-Prog-ID
- MOVE SPI-Current-Token-UC TO SR-Token-UC
- MOVE SPI-Current-Token TO SR-Token
- MOVE SPI-Current-Section TO SR-Section
- MOVE SPI-Current-Line-No TO SR-Line-No-Ref
- MOVE "*" TO SR-Ref-Flag
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 364-Set-Ref.
- MOVE SPACES TO Sort-Rec
- MOVE SPI-Current-Program-ID TO SR-Prog-ID
- MOVE SPI-Current-Token-UC TO SR-Token-UC
- MOVE SPI-Current-Token TO SR-Token
- MOVE SPI-Current-Section TO SR-Section
- MOVE SPI-Current-Line-No TO SR-Line-No-Ref
- .
- /
- 400-Produce-Xref-Listing SECTION.
- 401-Init.
- MOVE SPACES TO Detail-Line-X
- Group-Indicators
- MOVE 0 TO I
- Lines-Left
-GC0710 MOVE 'N' TO F-Duplicate
- .
-
- 402-Process-Sorted-Recs.
- PERFORM FOREVER
- RETURN Sort-File AT END
- EXIT PERFORM
- END-RETURN
- IF SR-Prog-ID NOT = GI-Prog-ID
- OR SR-Token-UC NOT = GI-Token
-GC0710 MOVE 'N' TO F-Duplicate
- IF Detail-Line-X NOT = SPACES
- PERFORM 410-Generate-Report-Line
- END-IF
- IF SR-Prog-ID NOT = GI-Prog-ID
- MOVE 0 TO Lines-Left
- END-IF
- MOVE SR-Prog-ID TO GI-Prog-ID
- MOVE SR-Token-UC TO GI-Token
- END-IF
-GC0710 IF SR-Token-UC = GI-Token
-GC0710 AND SR-Line-No-Def NOT = SPACES
-GC0710 AND Detail-Line-X NOT = SPACES
-GC0710 MOVE 'Y' TO F-Duplicate
-GC0710 PERFORM 410-Generate-Report-Line
-GC0710 MOVE 0 TO I
-GC0710 MOVE SR-Prog-ID TO DLX-Prog-ID
-GC0710 MOVE ' (Duplicate Definition)' TO DLX-Token
-GC0710 MOVE SR-Section TO DLX-Section
-GC0710 MOVE SR-Line-No-Def TO DLX-Line-No-Def
-GC0710 EXIT PERFORM CYCLE
-GC0710 END-IF
-GC0710 IF SR-Token-UC = GI-Token
-GC0710 AND SR-Line-No-Def = SPACES
-GC0710 AND F-Duplicate = 'Y'
-GC0710 MOVE 'N' TO F-Duplicate
-GC0710 PERFORM 410-Generate-Report-Line
-GC0710 MOVE 0 TO I
-GC0710 MOVE SR-Prog-ID TO DLX-Prog-ID
-GC0710 MOVE ' (Duplicate References)' TO DLX-Token
-GC0710 END-IF
- IF Detail-Line-X = SPACES
- MOVE SR-Prog-ID TO DLX-Prog-ID
- MOVE SR-Token TO DLX-Token
- MOVE SR-Section TO DLX-Section
- IF SR-Line-No-Def NOT = SPACES
- MOVE SR-Line-No-Def TO DLX-Line-No-Def
- END-IF
- END-IF
- IF SR-Reference > '000000'
- ADD 1 TO I
- IF I > Line-Nos-Per-Rec
- PERFORM 410-Generate-Report-Line
- MOVE 1 TO I
- END-IF
- MOVE SR-Line-No-Ref TO DLX-Line-No-Ref (I)
- MOVE SR-Ref-Flag TO DLX-Ref-Flag (I)
- END-IF
- END-PERFORM
- IF Detail-Line-X NOT = SPACES
- PERFORM 410-Generate-Report-Line
- END-IF
- EXIT SECTION
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 410-Generate-Report-Line.
- IF Lines-Left < 1
- IF F-First-Record = "Y"
- MOVE "N" TO F-First-Record
- WRITE Report-Rec FROM Heading-1X BEFORE 1
- ELSE
- MOVE SPACES TO Report-Rec
- WRITE Report-Rec BEFORE PAGE
- MOVE SPACES TO Report-Rec
- WRITE Report-Rec BEFORE 1
- WRITE Report-Rec FROM Heading-1X BEFORE 1
- END-IF
- WRITE Report-Rec FROM Heading-2 BEFORE 1
- WRITE Report-Rec FROM Heading-4X BEFORE 1
- WRITE Report-Rec FROM Heading-5X BEFORE 1
- COMPUTE
- Lines-Left = Lines-Per-Page - 4
- END-COMPUTE
- END-IF
- WRITE Report-Rec FROM Detail-Line-X BEFORE 1
- MOVE SPACES TO Detail-Line-X
- MOVE 0 TO I
- SUBTRACT 1 FROM Lines-Left
- .
- /
- 500-Produce-Source-Listing SECTION.
- 501-Generate-Source-Listing.
- OPEN INPUT Source-Code
- Expand-Code
- MOVE 0 TO Source-Line-No
- PERFORM FOREVER
- READ Expand-Code AT END
- EXIT PERFORM
- END-READ
- IF ECR-1 = "#"
- PERFORM 510-Control-Record
- ELSE
- PERFORM 520-Expand-Code-Record
- END-IF
- END-PERFORM
- CLOSE Source-Code
- Expand-Code
- EXIT SECTION
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 510-Control-Record.
- UNSTRING ECR-2-256
- DELIMITED BY '"'
- INTO PIC-X10, PIC-X256, Dummy
- END-UNSTRING
- IF TRIM(PIC-X256,Trailing) = TRIM(Program-Path,Trailing) *> Main Pgm
- SET In-Main-Module TO TRUE
- IF Source-Line-No > 0
- READ Expand-Code END-READ
- END-IF
- ELSE *> COPY
- SET In-Copybook TO TRUE
- END-IF
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 520-Expand-Code-Record.
- IF In-Main-Module
- ADD 1 To SPI-Current-Line-No
- READ Source-Code AT END NEXT SENTENCE END-READ
- ADD 1 TO Source-Line-No
- MOVE SPACES TO Detail-Line-S
- MOVE Source-Line-No TO DLS-Line-No
- MOVE SCR-1-128 TO DLS-Statement
-GC0410 IF SCR-7 = "/"
-GC0410 MOVE 0 TO Lines-Left
-GC0410 END-IF
- PERFORM 530-Generate-Source-Line
- IF SCR-129-256 NOT = SPACES
- MOVE SPACES TO Detail-Line-S
- MOVE SCR-129-256 TO DLS-Statement
- PERFORM 530-Generate-Source-Line
- END-IF
- ELSE
- IF Expand-Code-Rec NOT = SPACES
- MOVE SPACES TO Detail-Line-S
- MOVE ECR-1-128 TO DLS-Statement
- PERFORM 530-Generate-Source-Line
- IF ECR-129-256 NOT = SPACES
- MOVE SPACES TO Detail-Line-S
- MOVE ECR-129-256 TO DLS-Statement
- PERFORM 530-Generate-Source-Line
- END-IF
- END-IF
- END-IF
- .
- *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- 530-Generate-Source-Line.
- IF Lines-Left < 1
- IF F-First-Record = "Y"
- MOVE "N" TO F-First-Record
- WRITE Report-Rec FROM Heading-1S BEFORE 1
- ELSE
- MOVE SPACES TO Report-Rec
- WRITE Report-Rec BEFORE PAGE
- MOVE SPACES TO Report-Rec
- WRITE Report-Rec BEFORE 1
- WRITE Report-Rec FROM Heading-1S BEFORE 1
- END-IF
- WRITE Report-Rec FROM Heading-2 BEFORE 1
- WRITE Report-Rec FROM Heading-4S BEFORE 1
- WRITE Report-Rec FROM Heading-5S BEFORE 1
- COMPUTE
- Lines-Left = Lines-Per-Page - 4
- END-COMPUTE
- END-IF
- WRITE Report-Rec FROM Detail-Line-S BEFORE 1
- MOVE SPACES TO Detail-Line-S
- SUBTRACT 1 FROM Lines-Left
- .
-
END PROGRAM LISTING.
diff --git a/tests/examplefiles/example.coffee b/tests/examplefiles/example.coffee new file mode 100644 index 00000000..2cbd1df3 --- /dev/null +++ b/tests/examplefiles/example.coffee @@ -0,0 +1,27 @@ +# function arrows + +methodA:-> 'A' +methodB:=> 'B' +methodC:()=> 'C' +methodD:()-> 'D' +methodE:(a,b)-> 'E' +methodF:(c,d)-> 'F' +-> 'G' +=> 'H' + +(-> 'I') +(=> 'J') + +# strings + +"#{wow}" +"w#{wow}w" +"#wow" +"wow#" +"w#ow" + +'#{wow}' +'w#{wow}w' +'#wow' +'wow#' +'w#ow' diff --git a/tests/examplefiles/example.e b/tests/examplefiles/example.e new file mode 100644 index 00000000..2e43954b --- /dev/null +++ b/tests/examplefiles/example.e @@ -0,0 +1,124 @@ +note + description : "[ + This is use to have almost every language element." + + That way, I can correctly test the lexer. %]" + + Don't try to understand what it does. It's not even compilling. + ]" + date : "August 6, 2013" + revision : "0.1" + +class + SAMPLE + +inherit + ARGUMENTS + rename + Command_line as Caller_command, + command_name as Application_name + undefine + out + end + ANY + export + {ANY} out + redefine + out + end + + + +create + make + +convert + as_boolean: {BOOLEAN} + +feature {NONE} -- Initialization + + make + -- Run application. + local + i1_:expanded INTEGER + f_1:REAL_64 + l_char:CHARACTER_8 + do + l_char:='!' + l_char:='%'' + l_char:='%%' + i1_:=80 - 0x2F0C // 0C70 \\ 0b10110 * 1; + f_1:=0.1 / .567 + f_1:=34. + f_1:=12345.67890 + inspect i1_ + when 1 then + io.output.put_integer (i1_) -- Comment + else + io.output.put_real (f_1.truncated_to_real) + end + io.output.put_string (CuRrEnt.out) -- Comment + (agent funct_1).call([1,2,"Coucou"]) + end + +feature -- Access + + funct_1(x,y:separate INTEGER;a_text:READABLE_STRING_GENERAL):detachable BOOLEAN + obsolete "This function is obsolete" + require + Is_Attached: AttAched a_text + local + l_list:LIST[like x] + do + if (NOT a_text.is_empty=TrUe or elSe ((x<0 aNd x>10) oR (y>0 and then y<10))) xor True thEn + ResuLT := FalSe + elseif (acROss l_list as la_list SoMe la_list.item<0 end) implies a_text.is_boolean then + ResuLT := FalSe + else + Result := TruE + eND + from + l_list.start + until + l_list.exhausted + loop + l_list.forth + variant + l_list.count - l_list.index + end + check Current /= Void end + debug print("%"Here%"%N") end + ensure + Is_Cool_Not_Change: is_cool = old is_cool + end + + is_cool:BOOLEAN + attribute + Result:=False + end + + froZen c_malloc: POINTER is + exTErnal + "C inline use <stdlib.h>" + alIAs + "malloc (1)" + end + + as_boolean:BOOLEAN + do + Result:=True + rescue + retry + end + +feature {ANY} -- The redefine feature + + out:STRING_8 + once + reSUlt:=PrecursOr {ANY} + Result := "Hello Worl"+('d').out + end + +invariant + Always_Cool: is_cool +end diff --git a/tests/examplefiles/example.f90 b/tests/examplefiles/example.f90 new file mode 100644 index 00000000..40462189 --- /dev/null +++ b/tests/examplefiles/example.f90 @@ -0,0 +1,8 @@ +program main + integer, parameter :: mykind = selected_real_kind() + print *, 1 + print *, 1_mykind + print *, 1. + print *, 1._mykind + print *, (1., 1._mykind) +end program main diff --git a/tests/examplefiles/example.feature b/tests/examplefiles/example.feature new file mode 100644 index 00000000..a26268da --- /dev/null +++ b/tests/examplefiles/example.feature @@ -0,0 +1,16 @@ +# First comment +Feature: My amazing feature + Feature description line 1 + Feature description line 2 + +#comment +Scenario Outline: My detailed scenario #string + Given That <x> is set + When When I <subtract> + Then I should get the <remain#der> + + # indented comment + Examples: + | x | subtract | remain#der | + | 12 | 5\|3 | #73 | + | #the | 10 | 15 | diff --git a/tests/examplefiles/example.gd b/tests/examplefiles/example.gd new file mode 100644 index 00000000..c285ea32 --- /dev/null +++ b/tests/examplefiles/example.gd @@ -0,0 +1,23 @@ +############################################################################# +## +#W example.gd +## +## This file contains a sample of a GAP declaration file. +## +DeclareProperty( "SomeProperty", IsLeftModule ); +DeclareGlobalFunction( "SomeGlobalFunction" ); + + +############################################################################# +## +#C IsQuuxFrobnicator(<R>) +## +## <ManSection> +## <Filt Name="IsQuuxFrobnicator" Arg='R' Type='Category'/> +## +## <Description> +## Tests whether R is a quux frobnicator. +## </Description> +## </ManSection> +## +DeclareSynonym( "IsQuuxFrobnicator", IsField and IsGroup ); diff --git a/tests/examplefiles/example.gi b/tests/examplefiles/example.gi new file mode 100644 index 00000000..c9c5e55d --- /dev/null +++ b/tests/examplefiles/example.gi @@ -0,0 +1,64 @@ +############################################################################# +## +#W example.gd +## +## This file contains a sample of a GAP implementation file. +## + + +############################################################################# +## +#M SomeOperation( <val> ) +## +## performs some operation on <val> +## +InstallMethod( SomeProperty, + "for left modules", + [ IsLeftModule ], 0, + function( M ) + if IsFreeLeftModule( M ) and not IsTrivial( M ) then + return true; + fi; + TryNextMethod(); + end ); + + + +############################################################################# +## +#F SomeGlobalFunction( ) +## +## A global variadic funfion. +## +InstallGlobalFunction( SomeGlobalFunction, function( arg ) + if Length( arg ) = 3 then + return arg[1] + arg[2] * arg[3]; + elif Length( arg ) = 2 then + return arg[1] - arg[2] + else + Error( "usage: SomeGlobalFunction( <x>, <y>[, <z>] )" ); + fi; + end ); + + +# +# A plain function. +# +SomeFunc := function(x, y) + local z, func, tmp, j; + z := x * 1.0; + y := 17^17 - y; + func := a -> a mod 5; + tmp := List( [1..50], func ); + while y > 0 do + for j in tmp do + Print(j, "\n"); + od; + repeat + y := y - 1; + until 0 < 1; + y := y -1; + od; + return z; +end; +
\ No newline at end of file diff --git a/tests/examplefiles/example.golo b/tests/examplefiles/example.golo new file mode 100644 index 00000000..92ff78b5 --- /dev/null +++ b/tests/examplefiles/example.golo @@ -0,0 +1,113 @@ +# +# Comments +# + +module pygments.Example + +import some.Module + +local function foo = |a, b| -> a + b + +---- +golodoc string +---- +augment java.util.Collection { + + ---- + sub doc + ---- + function plop = |this, v| { + return this: length() + v + } +} + +function bar = |a, b| { + let msg = "a string" + var tmp = "" + tmp = tmp + a: toString() + println(tmp + b) +} + +function baz = { + foreach i in range(0, 5) { + if i % 2 == 0 and true or false { + print("e") + } else { + print("o") + } + } +} + +function userMatch = |v| -> + match { + when v % 2 == 0 then "e" + otherwise "o" + } +} + +function add = |x| -> |y| -> x + y + +let aChar = 'a' + +let multiline = +""" +foo +bar +baz +""" + +local function myObj = -> DynamicObject(): + name("foo"): + age(25): + define("meth", |this| -> this: name() + this: age() + +---- +Golo doc string +---- +function nullTest = { + let m = map[ + ["a", 1], + ["b", 2] + ] + + println(map: get("a") orIfNull 0) + println(map: get("b")?: toString() orIfNull "0") + +} + +struct Point = { x, y } + +function deco1 = |fun| { + return |args...| { + return "deco1 + " + fun: invokeWithArguments(args) + } +} + +@deco1 +function decofoo = |a| { + return "foo: " + a +} + +@deco1 +function decobar = |a| -> "bar: " + a + +function deco2 = |fun| { + return |args...| { + return "deco2 + " + fun: invokeWithArguments(args) + } +} + +@deco2 +@deco1 +function decobaz = |a| -> "baz: " + a + +let deco3 = ^deco1: andThen(^deco2) + +@deco3 +function decospam = |a| -> "spam: " + a + +@another.Module.deco +function ping = -> "pong" + +@deco("with", params) +function gnop = -> "gnip" diff --git a/tests/examplefiles/example.groovy b/tests/examplefiles/example.groovy new file mode 100644 index 00000000..25ef2eab --- /dev/null +++ b/tests/examplefiles/example.groovy @@ -0,0 +1,2 @@ +#!/usr/bin/env groovy +println "Hello World" diff --git a/tests/examplefiles/example.hs b/tests/examplefiles/example.hs new file mode 100644 index 00000000..f5e2b555 --- /dev/null +++ b/tests/examplefiles/example.hs @@ -0,0 +1,31 @@ +module ĈrazyThings where + +import "base" Data.Char +import "base" Data.Char (isControl, isSpace) +import "base" Data.Char (isControl, --isSpace) + isSpace) +import "base" Data.Char (isControl, -- isSpace) + isSpace) + +(-->) :: Num a => a -- signature +(-->) = 2 -- >implementation + +--test comment +-- test comment + +main :: IO () +main = putStrLn "hello world" + +gádd x y = x + y +ádd x y = x + y + + +data ĈrazyThings = + Ĉar | + House | + Peár + deriving (Show, Eq) + +-- some char literals: + +charl = ['"', 'a', '\ESC', '\'', ' '] diff --git a/tests/examplefiles/example.hx b/tests/examplefiles/example.hx index fd93bb49..7584fc81 100644 --- a/tests/examplefiles/example.hx +++ b/tests/examplefiles/example.hx @@ -139,4 +139,54 @@ typedef Pt2 = { y:Float, ?z:Float, //optional z add : Point -> Void, -}
\ No newline at end of file +} + + +//top-level class members +public function test(); +private var attr(get, set) = 1; + + +//pre-proc number +public static inline function indexOf<T>(arr:Array<T>, v:T) : Int +{ + #if (haxe_ver >= 3.1) + return arr.indexOf(v); + #else + #if (flash || js) + return untyped arr.indexOf(v); + #else + return std.Lambda.indexOf(arr, v); + #end + #end +} + +//macro reification +var e = macro var $myVar = 0; +var e = macro ${v}.toLowerCase(); +var e = macro o.$myField; +var e = macro { $myField : 0 }; +var e = macro $i{varName}++; +var e = macro $v{myStr}; +var args = [macro "sub", macro 3]; +var e = macro "Hello".toLowerCase($a{args}); +(macro $i{tmp}.addAtom($v{name}, $atom)).finalize(op.pos); + +var c = macro class MyClass { + public function new() { } + public function $funcName() { + trace($v{funcName} + " was called"); + } +} + +var c = macro interface IClass {}; + +//macro class could have no name... +var def = macro class { + private inline function new(loader) this = loader; + private var loader(get,never) : $loaderType; + inline private function get_loader() : $loaderType return this; +}; + +//ECheckType +var f = (123:Float);
\ No newline at end of file diff --git a/tests/examplefiles/example.i6t b/tests/examplefiles/example.i6t new file mode 100644 index 00000000..0f41b425 --- /dev/null +++ b/tests/examplefiles/example.i6t @@ -0,0 +1,32 @@ +B/examt: Example Template.
+
+@Purpose: To show the syntax of I6T, specifically the parts relating to the
+inclusion of I7 and at signs in the first column.
+
+@-------------------------------------------------------------------------------
+
+@p Lines.
+
+@c
+{-lines:type}
+! This is a comment.
+{-endlines}
+
+@-This line begins with @-, so it is ignored.
+
+@p Paragraph.
+This is a paragraph.
+@p Another paragraph.
+So
+
+is
+
+this.
+
+@Purpose: This purpose line is ignored.
+
+@c At signs and (+ +).
+[ Foo i;
+print (+score [an I7 value]+), "^";
+@add sp 1 -> i; ! Assembly works even in the first column.
+];
diff --git a/tests/examplefiles/example.i7x b/tests/examplefiles/example.i7x new file mode 100644 index 00000000..ab94ac69 --- /dev/null +++ b/tests/examplefiles/example.i7x @@ -0,0 +1,45 @@ +example by David Corbett begins here.
+
+"Implements testable examples."
+
+An example is a kind of thing. An example can be tested. An example is seldom tested.
+
+example ends here.
+
+----
+[The] documentation [starts here.]
+----
+
+This extension adds examples, which may be tested.
+
+Chapter: Usage
+
+To add an example to the story, we write:
+
+ The foobar is an example.
+
+To interact with it in Inform 6, we write something like:
+
+ To say (E - example): (-
+ print (object) {E};
+ -).
+ [The IDE's documentation viewer does not display the closing -). I don't know how to fix that.]
+
+Section: Testing
+
+We can make an example be tested using:
+
+ now the foobar is tested;
+
+Example: * Exempli Gratia - A simple example.
+
+ *: "Exempli Gratia"
+
+ Include example by David Corbett.
+
+ The Kitchen is a room. The egg is an example, here.
+
+ Before dropping the egg:
+ now the egg is tested.
+
+ Test me with "get egg / drop egg".
diff --git a/tests/examplefiles/example.inf b/tests/examplefiles/example.inf new file mode 100644 index 00000000..73cdd087 --- /dev/null +++ b/tests/examplefiles/example.inf @@ -0,0 +1,374 @@ +!% $SMALL ! This is ICL, not a comment. +!% -w + +!% A comprehensive test of Inform6Lexer. + +Switches d2SDq; + +Constant Story "Informal Testing"; +Constant Headline "^Not a game.^";!% This is a comment, not ICL. + +Release 2; +Serial "140308"; +Version 5; + +Ifndef TARGET_ZCODE; +Ifndef TARGET_GLULX; +Ifndef WORDSIZE; +Default WORDSIZE 2; +Constant TARGET_ZCODE; +Endif; +Endif; +Endif; + +Ifv3; Message "Compiling to version 3"; Endif; +Ifv5; Message "Not compiling to version 3"; endif; +ifdef TARGET_ZCODE; +#IFTRUE (#version_number == 5); +Message "Compiling to version 5"; +#ENDIF; +endif ; + +Replace CreatureTest; + +Include "Parser"; +Include "VerbLib"; + +# ! A hash is optional at the top level. +Object kitchen "Kitchen" + with description "You are in a kitchen.", + arr 1 2 3 4, + has light; + +#[ Initialise; + location = kitchen; + print "v"; inversion; "^"; +]; + +Ifdef VN_1633; +Replace IsSeeThrough IsSeeThroughOrig; +[ IsSeeThrough * o; + return o hasnt opaque || IsSeeThroughOrig(o); +]; +Endif; + +Abbreviate "test"; + +Array table buffer 260; + +Attribute reversed; +Attribute opaque alias locked; +Constant to reversed; + +Property long additive additive long alias; +Property long long long wingspan alias alias; + +Class Flier with wingspan 5; +Class Bird(10) has animate class Flier with wingspan 2; + +Constant Constant1; +Constant Constant2 Constant1; +Constant Constant3 = Constant2; +Ifdef VN_1633; Undef Constant; Endif; + +Ifdef VN_1633; +Dictionary 'word' 1 2; +Ifnot; +Dictionary dict_word "word"; +Endif; + +Fake_action NotReal; + +Global global1; +Global global2 = 69105; + +Lowstring low_string "low string"; + +Iftrue false; +Message error "Uh-oh!^~false~ shouldn't be ~true~."; +Endif; +Iffalse true; +Message fatalerror "Uh-oh!^~true~ shouldn't be ~false~."; +Endif; + +Nearby person "person" + with name 'person', + description "This person is barely implemented.", + life [ * x y z; + Ask: print_ret (The) self, " says nothing."; + Answer: print (The) self, " didn't say anything.^"; rfalse; + ] + has has animate transparent; + +Object -> -> test_tube "test tube" + with name 'test' "tube" 'testtube', + has ~openable ~opaque container; + +Bird -> pigeon + with name 'pigeon', + description [; + "The pigeon has a wingspan of ", self.&wingspan-->0, " wing units."; + ]; + +Object -> "thimble" with name 'thimble'; + +Object -> pebble "pebble" with name 'pebble'; + +Ifdef TARGET_ZCODE; Trace objects; Endif; + +Statusline score; + +Stub StubR 3; + +Ifdef TARGET_ZCODE; +Zcharacter "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "123456789.,!?_#'0/@{005C}-:()"; +Zcharacter table '@!!' '@<<' '@'A'; +Zcharacter table + '@AE' '@{dc}' '@et' '@:y'; +Ifnot; +Ifdef TARGET_GLULX; +Message "Glulx doesn't use ~Zcharacter~.^Oh well."; ! '~' and '^' work here. +Ifnot; +Message warning "Uh-oh! ^~^"; ! They don't work in other Messages. +Endif; +Endif; + +Include "Grammar"; + +Verb"acquire"'collect'='take'; + +[ NounFilter; return noun ofclass Bird; ]; + +[ ScopeFilter obj; + switch (scope_stage) { + 1: rtrue; + 2: objectloop (obj in compass) PlaceInScope(obj); + 3: "Nothing is in scope."; + } +]; + +Verb meta "t" 'test' + * 'held' held -> TestHeld + * number -> TestNumber + * reversed -> TestAttribute + * 'creature' creature -> TestCreature + * 'multiheld' multiheld -> TestMultiheld + * 'm' multiexcept 'into'/"in" noun -> TestMultiexcept + * 'm' multiinside 'from' noun -> TestMultiinside + * multi -> TestMulti + * 'filter'/'f' noun=NounFilter -> TestNounFilter + * 'filter'/'f' scope=ScopeFilter -> TestScopeFilter + * 'special' special -> TestSpecial + * topic -> TestTopic; + +Verb 'reverse' 'swap' 'exchange' + * held 'for' noun -> reverse + * noun 'with' noun -> reverse reverse; + +Extend "t" last * noun -> TestNoun; + +Extend 't' first * -> Test; + +Extend 'wave' replace * -> NewWave; + +Extend only 'feel' 'touch' replace * noun -> Feel; + +[ TestSub a b o; + string 25 low_string; + print "Test what?> "; + table->0 = 260; + parse->0 = 61; + #Ifdef TARGET_ZCODE; + read buffer parse; + #Ifnot; ! TARGET_GLULX + KeyboardPrimitive(buffer, parse); + #Endif; ! TARGET_ + switch (parse-->1) { + 'save': + #Ifdef TARGET_ZCODE; + #Ifv3; + @save ?saved; + #Ifnot; + save saved; + #Endif; + #Endif; + print "Saving failed.^"; + 'restore': + #Ifdef TARGET_ZCODE; + restore saved; + #Endif; + print "Restoring failed.^"; + 'restart': + @restart; + 'quit', 'q//': + quit; + return 2; rtrue; rfalse; return; + 'print', 'p//': + print "Print:^", + " (string): ", (string) "xyzzy^", + " (number): ", (number) 123, "^", + " (char): ", (char) 'x', "^", + " (address): ", (address) 'plugh//p', "^", + " (The): ", (The) person, "^", + " (the): ", (the) person, "^", + " (A): ", (A) person, "^", + " (a): ", (a) person, "^", + " (an): ", (an) person, "^", + " (name): ", (name) person, "^", + " (object): ", (object) person, "^", + " (property): ", (property) alias, "^", + " (<routine>): ", (LanguageNumber) 123, "^", + " <expression>: ", a * 2 - 1, "^", + " (<expression>): ", (a + person), "^"; + print "Escapes:^", + " by mnemonic: @!! @<< @'A @AE @et @:y^", + " by decimal value: @@64 @@126^", + " by Unicode value: @{DC}@{002b}^", + " by string variable: @25^"; + 'font', 'style': + font off; print "font off^"; + font on; print "font on^"; + style reverse; print "style reverse^"; style roman; + style bold; print "style bold^"; + style underline; print "style underline^"; + style fixed; print "style fixed^"; + style roman; print "style roman^"; + 'statements': + spaces 8; + objectloop (o) { + print "objectloop (o): ", (the) o, "^"; + } + objectloop (o in compass) { ! 'in' is a keyword + print "objectloop (o in compass): ", (the) o, "^"; + } + objectloop (o in compass && true) { ! 'in' is an operator + print "objectloop (o in compass && true): ", (the) o, "^"; + } + objectloop (o from se_obj) { + print "objectloop (o from se_obj): ", (the) o, "^"; + } + objectloop (o near person) { + print "objectloop (o near person): ", (the) o, "^"; + } + #Ifdef TARGET_ZCODE; + #Trace assembly on; +@ ! This is assembly. + add -4 ($$1+$3)*2 -> b; + @get_sibling test_tube -> b ?saved; + @inc [b]; + @je sp (1+3*0) ? equal; + @je 1 ((sp)) ?~ different; + .! This is a label: + equal; + print "sp == 1^"; + jump label; + .different; + print "sp @@126= 1^"; + .label; + #Trace off; #Endif; ! TARGET_ZCODE + a = random(10); + switch (a) { + 1, 9: + box "Testing oneself is best when done alone." + " -- Jimmy Carter"; + 2, 6, to, 3 to 5, to to to: + <Take pigeon>; + #Ifdef VN_1633; + <Jump, person>; + #Endif; + a = ##Drop; + < ! The angle brackets may be separated by whitespace. + < (a) pigeon > >; + default: + do { + give person general ~general; + } until (person provides life && ~~false); + if (a == 7) a = 4; + else a = 5; + } + 'expressions': + a = 1+1-1*1/1%1&1|1&&1||1==(1~=(1>(1<(1>=(1<=1))))); + a++; ++a; a--; --a; + a = person.life; + a = kitchen.&arr; + a = kitchen.#arr; + a = Bird::wingspan; + a = kitchen has general; + a = kitchen hasnt general; + a = kitchen provides arr; + a = person in kitchen; + a = person notin kitchen; + a = person ofclass Bird; + a = a == 0 or 1; + a = StubR(); + a = StubR(a); + a = StubR(, a); + a = "string"; + a = 'word'; + a = '''; ! character + a = $09afAF; + a = $$01; + a = ##Eat; a = #a$Eat; + a = #g$self; + a = #n$!word; + a = #r$StubR; + a = #dict_par1; + default: + for (a = 2, b = a; (a < buffer->1 + 2) && (Bird::wingspan): ++a, b--) { + print (char) buffer->a; + } + new_line; + for (::) break; + } + .saved;; +]; + +[ TestNumberSub; + print_ret parsed_number, " is ", (number) parsed_number, "."; +]; + +[ TestAttributeSub; print_ret (The) noun, " has been reversed."; ]; + +[ CreatureTest obj; return obj has animate; ]; + +[ TestCreatureSub; print_ret (The) noun, " is a creature."; ]; + +[ TestMultiheldSub; print_ret "You are holding ", (the) noun, "."; ]; + +[ TestMultiexceptSub; "You test ", (the) noun, " with ", (the) second, "."; ]; + +[ TestMultiinsideSub; "You test ", (the) noun, " from ", (the) second, "."; ]; + +[ TestMultiSub; print_ret (The) noun, " is a thing."; ]; + +[ TestNounFilterSub; print_ret (The) noun, " is a bird."; ]; + +[ TestScopeFilterSub; print_ret (The) noun, " is a direction."; ]; + +[ TestSpecialSub; "Your lucky number is ", parsed_number, "."; ]; + +[ TestTopicSub; "You discuss a topic."; ]; + +[ TestNounSub; "That is ", (a) noun, "."; ]; + +[ TestHeldSub; "You are holding ", (a) noun, "."; ]; + +[ NewWaveSub; "That would be foolish."; ]; + +[ FeelSub; print_ret (The) noun, " feels normal."; ]; + +[ ReverseSub from; + from = parent(noun); + move noun to parent(second); + if (from == to) + move second to to; + else + move second to from; + give noun to; + from = to; + give second from; + "You swap ", (the) noun, " and ", (the) second, "."; +]; + +End: The End directive ends the source code. diff --git a/tests/examplefiles/example.j b/tests/examplefiles/example.j new file mode 100644 index 00000000..16cdde86 --- /dev/null +++ b/tests/examplefiles/example.j @@ -0,0 +1,564 @@ +; Example JVM assembly +; Tested with JasminXT 2.4 + +.bytecode 49.0 +.source HelloWorld.java +.class public final enum HelloWorld +.super java/lang/Object +.implements java/io/Serializable +.signature "Ljava/lang/Object;Ljava/io/Serializable;" +.enclosing method hw/jasmin.HelloWorldRunner.run()V +.deprecated +.annotation visible HelloWorld + I I = 0 +.end annotation +.debug "Happy debugging!" + +.inner interface public InnerInterface inner 'HelloWorld$InnerInterface' outer HelloWorld +.inner class public InnerClass inner HelloWorld$InnerClass outer 'HelloWorld' + +.field public volatile transient I I +.field static protected final serialVersionUID 'J' signature "TJ;" = 2147483648 +.field annotation protected 'protected' [[[Lcom/oracle/util/Checksums; + .deprecated + .signature "[[[Lcom/oracle/util/Checksums;" + .attribute foo "foo.txt" + .attribute 'foo' "foo.txt" +.end field +.field public newline I +.field public static defaultString 'Ljava/lang/String;' + +.method public <init>()V + .limit stack 3 +.line 7 + .var 0 is self LHelloWorld; from 0 to 1 + aload_0 + invokenonvirtual java/lang/Object/<init>()V + return +.end method + +.method static public main([Ljava/lang/String;)V + .limit locals 7 + .limit stack 10 + .throws java.lang/RuntimeException + .catch java/lang.ClassCastException from cast to 'extra_l' using /extra + .signature "([Ljava/lang/String;)V" + .stack + offset /Input + locals Object java/lang/String + locals Uninitialized 'End' + locals Uninitialized 0 + locals Top + locals Integer + locals Float + locals Long + locals Double + locals Null + locals UninitializedThis + stack Object java/lang/String + stack Uninitialized End + stack 'Uninitialized' 0 + stack 'Top' + stack Integer + stack Float + stack Long + stack Double + stack Null + stack UninitializedThis + .end stack + .stack use 1 locals + offset 'extra' + .end stack + .stack use locals + .end stack +.line 0xd + .var 0 is args [Ljava/lang/String; + aload_w 0 + arraylength + ifne /Input + iconst_1 + anewarray java/lang/String + checkcast [Ljava/lang/String; + astore_0 + aload_0 + iconst_0 + ldc "World" + dup + putstatic HelloWorld.defaultString Ljava/lang/String; + aastore +/Input: + iconst_2 + iconst_3 + multianewarray [[C 2 + astore_1 + aload_1 + iconst_0 + aaload + astore_2 + aload_1 + iconst_1 + aaload + astore_3 + +<<o: + aload_3 + iconst_0 + invokestatic HelloWorld/int()I + castore + +<<\u0020: + aload_3 + dconst_1 + dconst_0 + dsub + d2i + invokestatic HelloWorld/double()D + d2i + castore + +<<!: + aload_3 + lconst_0 + dup2 + lxor + lconst_1 + dup2 + ladd + lsub + lneg + l2i + invokestatic HelloWorld/long()J + l2i + castore + +<<H: + aload_2 + fconst_0 + fconst_1 + fconst_2 + dup_x2 + fdiv + fmul + f2l + l2i + swap + invokestatic HelloWorld/float(F)F + f2i + castore + +<<e : + aload_2 + iconst_1 + i2s + i2c + i2b + iconst_1 + newarray short + dup + iconst_0 + iconst_1 + newarray byte + dup + iconst_0 + sipush 0x65 + bastore + iconst_0 + baload + sastore + iconst_0 + saload + int2short + int2char + int2byte + castore + + <<l : + aload_2 + iconst_2 + bipush 0x1b +*2: + iconst_1 + ishl + dup + lookupswitch + 0: '/lookupswitch' + 0x6c: /lookupswitch + default: *2 +/lookupswitch: + castore + + ldc2_w 2 + dup2 + lcmp + .set i 4 + .set 'j' 5 + .var 4 is i I from 'i++' to End + .var 5 is j I signature "I" from i++ to End + istore 4 + goto 1 +i++: + iinc 4 1 +1: iconst_0 + istore_w 5 + goto_w 2 +j++: + iinc_w 5 1 +2: getstatic java/lang/System/out Ljava/io/PrintStream; + aload_1 + iload 4 + aaload + iload_w 5 + caload + invokevirtual java/io/PrintStream/print(C)V + iload 5 + iconst_1 + if_icmpne $+6 + jsr extra + iload 5 + iconst_2 + if_icmplt j++ + iconst_1 + iload 4 + if_icmpgt i++ + +<<\u00a0: + getstatic java/lang/System/out Ljava/io/PrintStream; + invokestatic HelloWorld/get"example()LHelloWorld; + getfield HelloWorld/newline I + invokevirtual java/io/PrintStream/print(C)V +End: + return + +extra: + astore 6 + iload 4 + tableswitch 0 1 + extra_l + extra_string + default: 'End' + nop +extra_string: + getstatic java/lang/System/out Ljava/io/PrintStream; + aload 0 + iconst_0 + aaload + invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V +cast: + ldc java/lang/String + checkcast java/lang/Class + pop + ldc Ljava/lang/String; + checkcast Ljava/lang/Class; + pop + iconst_1 + dup + newarray boolean + checkcast [Z + pop + newarray 'int' + checkcast HelloWorld + checkcast LHelloWorld; + pop +extra_l: + getstatic java/lang/System/out Ljava/io/PrintStream; + dup + ldc "\123.\456.\u006c.\n.\r.\t.\f.\b.\".\'.\\" + iconst_5 + invokeinterface java/lang/CharSequence/charAt(I)C 2 + invokevirtual java/io/PrintStream/print(C)V +/extra: + pop + ret 6 +.end method + +.method private static get"example()LHelloWorld; + .limit locals 3 + .limit stack 4 + .catch all from 7 to 53 using 59 + aconst_null + dup + dup + astore_w 0 +try: + goto $+0x11 +finally: + astore_w 2 + putfield HelloWorld/newline I + ret_w 2 + nop + aload_0 + areturn + ifnonnull $-2 + ifnull $+3 + new HelloWorld + dup + dup + invokespecial HelloWorld/<init>()V + astore 0 + aload 0 + monitorenter + monitorexit + new java/lang/RuntimeException + dup + invokespecial java/lang/RuntimeException/<init>()V + athrow + aconst_null +/try: + dup + aconst_null + if_acmpeq $+3 + areturn +catch: + jsr $+10 + aload_0 + dup + aconst_null + if_acmpne /try + areturn + astore_1 + aload_0 + ldc 10 + jsr_w finally + ret 1 +'single\u0020quoted\u0020label': ; Messes up [@ below if lexed sloppily +.end method + +.method varargs private static int()I + .annotation invisible HelloWorld + [@ [@ WhatIsThis??? = .annotation ; name, type, exttype + I I = 1 ; name, type + another-I I = 2 + Enum e Ljava/util/logging/Level; = FINE + .end annotation + .annotation + s s = "foo" + another-s s = "bar" + Enum [e Ljava/util/logging/Level; = FINE FINE 'FINE' FINE + .end annotation + float F = 123.456 + .end annotation + .annotation visibleparam 1 LHelloWorld; + x [I = 0x01 0x02 0x03 + y I = 2 + .end annotation + .annotation invisibleparam 255 HelloWorld + a F = 1.2 + b D = 3.4 + .end annotation + .annotation default + I = 0 + .end annotation + .limit locals 4 + .limit stack 20 + iconst_1 + newarray int + dup + dup + instanceof [Z + bipush 0x9 + bipush 0xB + iand + iconst_5 + iconst_4 + dup_x1 + iconst_m1 + iadd + bipush +-111 + ineg + swap + idiv + dup_x2 + dup + ishr + ishl + imul + ior + bipush -73 + ixor + isub + dup + iconst_1 + iadd + irem + iastore + iconst_0 + iaload + istore_0 + iload_0 + istore_1 + iload_1 + istore_2 + iload_2 + istore_3 + iload_3 + dup + dup + dup2_x1 + if_icmpeq $+33 + dup + dup + if_icmpge $+28 + dup + dup + if_icmple $+23 + dup + ifle $+19 + dup + ifeq $+15 + dup + iflt $+11 + dup + ifgt $+7 + dup + ifge $+3 + ireturn +.end method + +.method static private fpstrict double()D + .limit locals 7 + .limit stack 11 + dconst_1 + dconst_0 + dcmpg + newarray double + dup + dconst_0 + dup2 + dcmpl + ldc2_w 128. + ldc2_w -240.221d + dneg + ldc2_w 158.d + dup2 + dadd + dup2_x2 + drem + ddiv + pop2 + dconst_1 + dmul + d2f + f2d + d2l + l2i + iconst_2 + iushr + i2d + dastore + iconst_0 + daload + dstore_0 + dload_0 + dstore_1 + dload_1 + dstore_2 + dload_2 + dstore_3 + dload_3 + dstore 4 + dload 4 + dstore_w 5 + dload_w 5 + dreturn +.end method + +.method static long()J + .limit locals 7 + .limit stack 11 + iconst_1 + newarray long + dup + iconst_0 + ldc2_w 5718613688 + ldc2_w 3143486100 + ldc2_w 0x3 + ldiv + lmul + ldc2_w -10000000000 + lrem + ldc_w 0x60 + i2l + lor + ldc 0x33 + i2l + land + dup2 + iconst_1 + lshl + iconst_3 + lshr + iconst_3 + lushr + ladd + l2d + d2l + l2f + f2l + lastore + iconst_0 + laload + lstore_0 + lload_0 + lstore_1 + lload_1 + lstore_2 + lload_2 + lstore_3 + lload_3 + lstore 4 + lload 4 + lstore_w 5 + lload_w 5 + lreturn +.end method + +.method private static float(F)F + .limit locals 6 + .limit stack 9 + iconst_1 + newarray float + dup + fload_0 + dup + fcmpg + fload_0 + dup + dup + dup + dup2_x2 + fadd + fsub + fneg + frem + ldc 70 + i2f + fadd + fadd + swap + pop + fastore + fload_0 + dup + fcmpl + faload + fstore_0 + fload_0 + fstore_1 + fload_1 + fstore_2 + fload_2 + fstore_3 + fload_3 + fstore 4 + fload 4 + fstore_w 5 + fload_w 5 + freturn +.end method + +.method abstract bridge synthetic 'acc1()V' + breakpoint +.end method + +.method native synchronized acc2()V +.end method diff --git a/tests/examplefiles/example.java b/tests/examplefiles/example.java new file mode 100644 index 00000000..78f9d727 --- /dev/null +++ b/tests/examplefiles/example.java @@ -0,0 +1,16 @@ +class _PostUnico$deClassá +{void fo$o() {} + + void PostUnicodeFunctioná() { + láb$el: + break láb$el; + + } +} + +class áPreUnicode$Class +{ + public int $foo; + public int á$foo; + _PostUnico$deClassá áPreUnicodeFunction() { return null; } +} diff --git a/tests/examplefiles/example.jsonld b/tests/examplefiles/example.jsonld new file mode 100644 index 00000000..48787d75 --- /dev/null +++ b/tests/examplefiles/example.jsonld @@ -0,0 +1,27 @@ +{ + "@context": { + "schema": "http://schema.org/", + "name": "schema:name", + "body": "schema:articleBody", + "words": "schema:wordCount", + "post": { + "@id": "schema:blogPost", + "@container": "@index" + } + }, + "@id": "http://example.com/", + "@type": "schema:Blog", + "name": "World Financial News", + "post": { + "en": { + "@id": "http://example.com/posts/1/en", + "body": "World commodities were up today with heavy trading of crude oil...", + "words": 1539 + }, + "de": { + "@id": "http://example.com/posts/1/de", + "body": "Die Werte an Warenbörsen stiegen im Sog eines starken Handels von Rohöl...", + "words": 1204 + } + } +} diff --git a/tests/examplefiles/example.kal b/tests/examplefiles/example.kal new file mode 100644 index 00000000..c05c14ca --- /dev/null +++ b/tests/examplefiles/example.kal @@ -0,0 +1,75 @@ +#!/usr/bin/env kal + +# This demo executes GET requests in parallel and in series +# using `for` loops and `wait for` statements. + +# Notice how the serial GET requests always return in order +# and take longer in total. Parallel requests come back in +# order of receipt. + +http = require 'http' + +urls = ['http://www.google.com' + 'http://www.apple.com' + 'http://www.microsoft.com' + 'http://www.nodejs.org' + 'http://www.yahoo.com'] + +# This function does a GET request for each URL in series +# It will wait for a response from each request before moving on +# to the next request. Notice the output will be in the same order as the +# urls variable every time regardless of response time. +# It is a task rather than a function because it is called asynchronously +# This allows us to use `return` to implicitly call back +task series_demo() + # The `series` keyword is optional here (for loops are serial by default) + total_time = 0 + + for series url in urls + timer = new Date + + # we use the `safe` keyword because get is a "nonstandard" task + # that does not call back with an error argument + safe wait for response from http.get url + + delay = new Date() - timer + total_time += delay + + print "GET #{url} - #{response.statusCode} - #{response.connection.bytesRead} bytes - #{delay} ms" + + # because we are in a task rather than a function, this actually exectutes a callback + return total_time + +# This function does a GET request for each URL in parallel +# It will NOT wait for a response from each request before moving on +# to the next request. Notice the output will be determined by the order in which +# the requests complete! +task parallel_demo() + total_time = 0 + + # The `parallel` keyword is only meaningful here because the loop contains + # a `wait for` statement (meaning callbacks are used) + for parallel url in urls + timer = new Date + + # we use the `safe` keyword because get is a "nonstandard" task + # that does not call back with an error argument + safe wait for response from http.get url + + delay = new Date() - timer + total_time += delay + + print "GET #{url} - #{response.statusCode} - #{response.connection.bytesRead} bytes - #{delay}ms" + + # because we are in a task rather than a function, this actually exectutes a callback + return total_time + +print 'Series Requests...' +wait for time1 from series_demo() +print "Total duration #{time1}ms" + +print '' + +print 'Parallel Requests...' +wait for time2 from parallel_demo() +print "Total duration #{time2}ms" diff --git a/tests/examplefiles/example.liquid b/tests/examplefiles/example.liquid new file mode 100644 index 00000000..8f3ea9e9 --- /dev/null +++ b/tests/examplefiles/example.liquid @@ -0,0 +1,42 @@ +# This is an example file. Process it with `./pygmentize -O full -f html -o /liquid-example.html example.liquid`. + +{% raw %} +some {{raw}} liquid syntax + +{% raw %} +{% endraw %} + +Just regular text - what happens? + +{% comment %}My lovely {{comment}} {% comment %}{% endcomment %} + +{% custom_tag params: true %} +{% custom_block my="abc" c = false %} + Just usual {{liquid}}. +{% endcustom_block %} + +{% another_tag "my string param" %} + +{{ variable | upcase }} +{{ var.field | textilize | markdownify }} +{{ var.field.property | textilize | markdownify }} +{{ 'string' | truncate: 100 param='df"g' }} + +{% cycle '1', 2, var %} +{% cycle 'group1': '1', var, 2 %} +{% cycle group2: '1', var, 2 %} + +{% if a == 'B' %} +{% elsif a == 'C%}' %} +{% else %} +{% endif %} + +{% unless not a %} +{% else %} +{% endunless %} + +{% case a %} +{% when 'B' %} +{% when 'C' %} +{% else %} +{% endcase %}
\ No newline at end of file diff --git a/tests/examplefiles/example.ma b/tests/examplefiles/example.ma new file mode 100644 index 00000000..a8119ea5 --- /dev/null +++ b/tests/examplefiles/example.ma @@ -0,0 +1,8 @@ +1 + 1 (* This is a comment *) +Global` +SomeNamespace`Foo +f[x_, y__, 3, z___] := tsneirsnteintie "fosrt" neisnrteiasrn +E + 3 +Plus[1,Times[2,3]] +Map[#1 + #2&, SomePairList] +Plus[1.,-1,-1.,-1.0,]
\ No newline at end of file diff --git a/tests/examplefiles/example.mq4 b/tests/examplefiles/example.mq4 new file mode 100644 index 00000000..54a5fa60 --- /dev/null +++ b/tests/examplefiles/example.mq4 @@ -0,0 +1,187 @@ +//+------------------------------------------------------------------+
+//| PeriodConverter.mq4 |
+//| Copyright 2006-2014, MetaQuotes Software Corp. |
+//| http://www.metaquotes.net |
+//+------------------------------------------------------------------+
+#property copyright "2006-2014, MetaQuotes Software Corp."
+#property link "http://www.mql4.com"
+#property description "Period Converter to updated format of history base"
+#property strict
+#property show_inputs
+#include <WinUser32.mqh>
+
+input int InpPeriodMultiplier=3; // Period multiplier factor
+int ExtHandle=-1;
+//+------------------------------------------------------------------+
+//| script program start function |
+//+------------------------------------------------------------------+
+void OnStart()
+ {
+ datetime time0;
+ ulong last_fpos=0;
+ long last_volume=0;
+ int i,start_pos,periodseconds;
+ int hwnd=0,cnt=0;
+//---- History header
+ int file_version=401;
+ string c_copyright;
+ string c_symbol=Symbol();
+ int i_period=Period()*InpPeriodMultiplier;
+ int i_digits=Digits;
+ int i_unused[13];
+ MqlRates rate;
+//---
+ ExtHandle=FileOpenHistory(c_symbol+(string)i_period+".hst",FILE_BIN|FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_ANSI);
+ if(ExtHandle<0)
+ return;
+ c_copyright="(C)opyright 2003, MetaQuotes Software Corp.";
+ ArrayInitialize(i_unused,0);
+//--- write history file header
+ FileWriteInteger(ExtHandle,file_version,LONG_VALUE);
+ FileWriteString(ExtHandle,c_copyright,64);
+ FileWriteString(ExtHandle,c_symbol,12);
+ FileWriteInteger(ExtHandle,i_period,LONG_VALUE);
+ FileWriteInteger(ExtHandle,i_digits,LONG_VALUE);
+ FileWriteInteger(ExtHandle,0,LONG_VALUE);
+ FileWriteInteger(ExtHandle,0,LONG_VALUE);
+ FileWriteArray(ExtHandle,i_unused,0,13);
+//--- write history file
+ periodseconds=i_period*60;
+ start_pos=Bars-1;
+ rate.open=Open[start_pos];
+ rate.low=Low[start_pos];
+ rate.high=High[start_pos];
+ rate.tick_volume=(long)Volume[start_pos];
+ rate.spread=0;
+ rate.real_volume=0;
+ //--- normalize open time
+ rate.time=Time[start_pos]/periodseconds;
+ rate.time*=periodseconds;
+ for(i=start_pos-1; i>=0; i--)
+ {
+ if(IsStopped())
+ break;
+ time0=Time[i];
+ //--- history may be updated
+ if(i==0)
+ {
+ //--- modify index if history was updated
+ if(RefreshRates())
+ i=iBarShift(NULL,0,time0);
+ }
+ //---
+ if(time0>=rate.time+periodseconds || i==0)
+ {
+ if(i==0 && time0<rate.time+periodseconds)
+ {
+ rate.tick_volume+=(long)Volume[0];
+ if(rate.low>Low[0])
+ rate.low=Low[0];
+ if(rate.high<High[0])
+ rate.high=High[0];
+ rate.close=Close[0];
+ }
+ last_fpos=FileTell(ExtHandle);
+ last_volume=(long)Volume[i];
+ FileWriteStruct(ExtHandle,rate);
+ cnt++;
+ if(time0>=rate.time+periodseconds)
+ {
+ rate.time=time0/periodseconds;
+ rate.time*=periodseconds;
+ rate.open=Open[i];
+ rate.low=Low[i];
+ rate.high=High[i];
+ rate.close=Close[i];
+ rate.tick_volume=last_volume;
+ }
+ }
+ else
+ {
+ rate.tick_volume+=(long)Volume[i];
+ if(rate.low>Low[i])
+ rate.low=Low[i];
+ if(rate.high<High[i])
+ rate.high=High[i];
+ rate.close=Close[i];
+ }
+ }
+ FileFlush(ExtHandle);
+ Print(cnt," record(s) written");
+//--- collect incoming ticks
+ datetime last_time=LocalTime()-5;
+ while(!IsStopped())
+ {
+ datetime cur_time=LocalTime();
+ //--- check for new rates
+ if(RefreshRates())
+ {
+ time0=Time[0];
+ FileSeek(ExtHandle,last_fpos,SEEK_SET);
+ //--- is there current bar?
+ if(time0<rate.time+periodseconds)
+ {
+ rate.tick_volume+=(long)Volume[0]-last_volume;
+ last_volume=(long)Volume[0];
+ if(rate.low>Low[0])
+ rate.low=Low[0];
+ if(rate.high<High[0])
+ rate.high=High[0];
+ rate.close=Close[0];
+ }
+ else
+ {
+ //--- no, there is new bar
+ rate.tick_volume+=(long)Volume[1]-last_volume;
+ if(rate.low>Low[1])
+ rate.low=Low[1];
+ if(rate.high<High[1])
+ rate.high=High[1];
+ //--- write previous bar remains
+ FileWriteStruct(ExtHandle,rate);
+ last_fpos=FileTell(ExtHandle);
+ //----
+ rate.time=time0/periodseconds;
+ rate.time*=periodseconds;
+ rate.open=Open[0];
+ rate.low=Low[0];
+ rate.high=High[0];
+ rate.close=Close[0];
+ rate.tick_volume=(long)Volume[0];
+ last_volume=rate.tick_volume;
+ }
+ //----
+ FileWriteStruct(ExtHandle,rate);
+ FileFlush(ExtHandle);
+ //---
+ if(hwnd==0)
+ {
+ hwnd=WindowHandle(Symbol(),i_period);
+ if(hwnd!=0)
+ Print("Chart window detected");
+ }
+ //--- refresh window not frequently than 1 time in 2 seconds
+ if(hwnd!=0 && cur_time-last_time>=2)
+ {
+ PostMessageA(hwnd,WM_COMMAND,33324,0);
+ last_time=cur_time;
+ }
+ }
+ Sleep(50);
+ }
+//---
+ }
+//+------------------------------------------------------------------+
+//| |
+//+------------------------------------------------------------------+
+void OnDeinit(const int reason)
+ {
+//---
+ if(ExtHandle>=0)
+ {
+ FileClose(ExtHandle);
+ ExtHandle=-1;
+ }
+//---
+ }
+//+------------------------------------------------------------------+
\ No newline at end of file diff --git a/tests/examplefiles/example.mqh b/tests/examplefiles/example.mqh new file mode 100644 index 00000000..ee80ed52 --- /dev/null +++ b/tests/examplefiles/example.mqh @@ -0,0 +1,123 @@ +//+------------------------------------------------------------------+
+//| Array.mqh |
+//| Copyright 2009-2013, MetaQuotes Software Corp. |
+//| http://www.mql4.com |
+//+------------------------------------------------------------------+
+#include <Object.mqh>
+//+------------------------------------------------------------------+
+//| Class CArray |
+//| Purpose: Base class of dynamic arrays. |
+//| Derives from class CObject. |
+//+------------------------------------------------------------------+
+class CArray : public CObject
+ {
+protected:
+ int m_step_resize; // increment size of the array
+ int m_data_total; // number of elements
+ int m_data_max; // maximmum size of the array without memory reallocation
+ int m_sort_mode; // mode of array sorting
+
+public:
+ CArray(void);
+ ~CArray(void);
+ //--- methods of access to protected data
+ int Step(void) const { return(m_step_resize); }
+ bool Step(const int step);
+ int Total(void) const { return(m_data_total); }
+ int Available(void) const { return(m_data_max-m_data_total); }
+ int Max(void) const { return(m_data_max); }
+ bool IsSorted(const int mode=0) const { return(m_sort_mode==mode); }
+ int SortMode(void) const { return(m_sort_mode); }
+ //--- cleaning method
+ void Clear(void) { m_data_total=0; }
+ //--- methods for working with files
+ virtual bool Save(const int file_handle);
+ virtual bool Load(const int file_handle);
+ //--- sorting method
+ void Sort(const int mode=0);
+
+protected:
+ virtual void QuickSort(int beg,int end,const int mode=0) { }
+ };
+//+------------------------------------------------------------------+
+//| Constructor |
+//+------------------------------------------------------------------+
+CArray::CArray(void) : m_step_resize(16),
+ m_data_total(0),
+ m_data_max(0),
+ m_sort_mode(-1)
+ {
+ }
+//+------------------------------------------------------------------+
+//| Destructor |
+//+------------------------------------------------------------------+
+CArray::~CArray(void)
+ {
+ }
+//+------------------------------------------------------------------+
+//| Method Set for variable m_step_resize |
+//+------------------------------------------------------------------+
+bool CArray::Step(const int step)
+ {
+//--- check
+ if(step>0)
+ {
+ m_step_resize=step;
+ return(true);
+ }
+//--- failure
+ return(false);
+ }
+//+------------------------------------------------------------------+
+//| Sorting an array in ascending order |
+//+------------------------------------------------------------------+
+void CArray::Sort(const int mode)
+ {
+//--- check
+ if(IsSorted(mode))
+ return;
+ m_sort_mode=mode;
+ if(m_data_total<=1)
+ return;
+//--- sort
+ QuickSort(0,m_data_total-1,mode);
+ }
+//+------------------------------------------------------------------+
+//| Writing header of array to file |
+//+------------------------------------------------------------------+
+bool CArray::Save(const int file_handle)
+ {
+//--- check handle
+ if(file_handle!=INVALID_HANDLE)
+ {
+ //--- write start marker - 0xFFFFFFFFFFFFFFFF
+ if(FileWriteLong(file_handle,-1)==sizeof(long))
+ {
+ //--- write array type
+ if(FileWriteInteger(file_handle,Type(),INT_VALUE)==INT_VALUE)
+ return(true);
+ }
+ }
+//--- failure
+ return(false);
+ }
+//+------------------------------------------------------------------+
+//| Reading header of array from file |
+//+------------------------------------------------------------------+
+bool CArray::Load(const int file_handle)
+ {
+//--- check handle
+ if(file_handle!=INVALID_HANDLE)
+ {
+ //--- read and check start marker - 0xFFFFFFFFFFFFFFFF
+ if(FileReadLong(file_handle)==-1)
+ {
+ //--- read and check array type
+ if(FileReadInteger(file_handle,INT_VALUE)==Type())
+ return(true);
+ }
+ }
+//--- failure
+ return(false);
+ }
+//+------------------------------------------------------------------+
diff --git a/tests/examplefiles/example.ni b/tests/examplefiles/example.ni new file mode 100644 index 00000000..32279e80 --- /dev/null +++ b/tests/examplefiles/example.ni @@ -0,0 +1,57 @@ + | | |
+"Informal by Nature"
+[ * * * ]
+by
+[ * * * ]
+David Corbett
+
+[This is a [nested] comment.]
+
+Section 1 - Use option translation
+
+Use maximum tests of at least 100 translates as (-
+@c
+Constant MAX_TESTS = {N}; —). | Section 2
+
+A room has a number called size.
+
+The Kitchen is a room. "A nondescript kitchen.“ The Kitchen has size 2.
+
+When play begins:
+ say "Testing:[line break]";
+ test 0.
+
+To test (N — number): (—
+ if (Test({N}) == (+size of the Kitchen [this should succeed]+)) {-open—brace}
+ print ”Success.^”;
+ {-close-brace} else {
+ print “Failure.^";
+ }
+]; ! You shouldn't end a routine within a phrase definition, but it works.
+[ Unused;
+ #Include "\
+@p \
+"; ! At signs hold no power here.
+! Of course, the file "@p .h" must exist.
+-).
+
+Include (-!% This is not ICL.
+
+[ Test x;
+ if (x) {x++;}
+ {–! Single line comment.}
+@inc x;
+@p At signs.
+...
+@Purpose: ...
+...
+@-...
+@c ...
+@inc x;
+@c
+@c
+ return x;
+];
+@Purpose: ...
+@-------------------------------------------------------------------------------
+-).
diff --git a/tests/examplefiles/example.nix b/tests/examplefiles/example.nix new file mode 100644 index 00000000..515b686f --- /dev/null +++ b/tests/examplefiles/example.nix @@ -0,0 +1,80 @@ +{ stdenv, fetchurl, fetchgit, openssl, zlib, pcre, libxml2, libxslt, expat +, rtmp ? false +, fullWebDAV ? false +, syslog ? false +, moreheaders ? false, ...}: + +let + version = "1.4.4"; + mainSrc = fetchurl { + url = "http://nginx.org/download/nginx-${version}.tar.gz"; + sha256 = "1f82845mpgmhvm151fhn2cnqjggw9w7cvsqbva9rb320wmc9m63w"; + }; + + rtmp-ext = fetchgit { + url = git://github.com/arut/nginx-rtmp-module.git; + rev = "1cfb7aeb582789f3b15a03da5b662d1811e2a3f1"; + sha256 = "03ikfd2l8mzsjwx896l07rdrw5jn7jjfdiyl572yb9jfrnk48fwi"; + }; + + dav-ext = fetchgit { + url = git://github.com/arut/nginx-dav-ext-module.git; + rev = "54cebc1f21fc13391aae692c6cce672fa7986f9d"; + sha256 = "1dvpq1fg5rslnl05z8jc39sgnvh3akam9qxfl033akpczq1bh8nq"; + }; + + syslog-ext = fetchgit { + url = https://github.com/yaoweibin/nginx_syslog_patch.git; + rev = "165affd9741f0e30c4c8225da5e487d33832aca3"; + sha256 = "14dkkafjnbapp6jnvrjg9ip46j00cr8pqc2g7374z9aj7hrvdvhs"; + }; + + moreheaders-ext = fetchgit { + url = https://github.com/agentzh/headers-more-nginx-module.git; + rev = "refs/tags/v0.23"; + sha256 = "12pbjgsxnvcf2ff2i2qdn39q4cm5czlgrng96j8ml4cgxvnbdh39"; + }; +in + +stdenv.mkDerivation rec { + name = "nginx-${version}"; + src = mainSrc; + + buildInputs = [ openssl zlib pcre libxml2 libxslt + ] ++ stdenv.lib.optional fullWebDAV expat; + + patches = if syslog then [ "${syslog-ext}/syslog_1.4.0.patch" ] else []; + + configureFlags = [ + "--with-http_ssl_module" + "--with-http_spdy_module" + "--with-http_xslt_module" + "--with-http_sub_module" + "--with-http_dav_module" + "--with-http_gzip_static_module" + "--with-http_secure_link_module" + "--with-ipv6" + # Install destination problems + # "--with-http_perl_module" + ] ++ stdenv.lib.optional rtmp "--add-module=${rtmp-ext}" + ++ stdenv.lib.optional fullWebDAV "--add-module=${dav-ext}" + ++ stdenv.lib.optional syslog "--add-module=${syslog-ext}" + ++ stdenv.lib.optional moreheaders "--add-module=${moreheaders-ext}"; + + preConfigure = '' + export NIX_CFLAGS_COMPILE="$NIX_CFLAGS_COMPILE -I${libxml2 }/include/libxml2" + ''; + + # escape example + postInstall = '' + mv $out/sbin $out/bin ''' ''${ + ${ if true then ${ "" } else false } + ''; + + meta = { + description = "A reverse proxy and lightweight webserver"; + maintainers = [ stdenv.lib.maintainers.raskin]; + platforms = stdenv.lib.platforms.all; + inherit version; + }; +} diff --git a/tests/examplefiles/example.pp b/tests/examplefiles/example.pp new file mode 100644 index 00000000..ea697be2 --- /dev/null +++ b/tests/examplefiles/example.pp @@ -0,0 +1,8 @@ +exec { 'grep': + command => 'grep "\'" -rI *', + path => '/bin:/usr/bin', +} + +node default { + notify {"Hello World":;} +} diff --git a/tests/examplefiles/example.red b/tests/examplefiles/example.red new file mode 100644 index 00000000..37c17ef8 --- /dev/null +++ b/tests/examplefiles/example.red @@ -0,0 +1,257 @@ +Red [
+ Title: "Red console"
+ Author: ["Nenad Rakocevic" "Kaj de Vos"]
+ File: %console.red
+ Tabs: 4
+ Rights: "Copyright (C) 2012-2013 Nenad Rakocevic. All rights reserved."
+ License: {
+ Distributed under the Boost Software License, Version 1.0.
+ See https://github.com/dockimbel/Red/blob/master/BSL-License.txt
+ }
+ Purpose: "Just some code for testing Pygments colorizer"
+ Language: http://www.red-lang.org/
+]
+
+#system-global [
+ #either OS = 'Windows [
+ #import [
+ "kernel32.dll" stdcall [
+ AttachConsole: "AttachConsole" [
+ processID [integer!]
+ return: [integer!]
+ ]
+ SetConsoleTitle: "SetConsoleTitleA" [
+ title [c-string!]
+ return: [integer!]
+ ]
+ ReadConsole: "ReadConsoleA" [
+ consoleInput [integer!]
+ buffer [byte-ptr!]
+ charsToRead [integer!]
+ numberOfChars [int-ptr!]
+ inputControl [int-ptr!]
+ return: [integer!]
+ ]
+ ]
+ ]
+ line-buffer-size: 16 * 1024
+ line-buffer: allocate line-buffer-size
+ ][
+ #switch OS [
+ MacOSX [
+ #define ReadLine-library "libreadline.dylib"
+ ]
+ #default [
+ #define ReadLine-library "libreadline.so.6"
+ #define History-library "libhistory.so.6"
+ ]
+ ]
+ #import [
+ ReadLine-library cdecl [
+ read-line: "readline" [ ; Read a line from the console.
+ prompt [c-string!]
+ return: [c-string!]
+ ]
+ rl-bind-key: "rl_bind_key" [
+ key [integer!]
+ command [integer!]
+ return: [integer!]
+ ]
+ rl-insert: "rl_insert" [
+ count [integer!]
+ key [integer!]
+ return: [integer!]
+ ]
+ ]
+ #if OS <> 'MacOSX [
+ History-library cdecl [
+ add-history: "add_history" [ ; Add line to the history.
+ line [c-string!]
+ ]
+ ]
+ ]
+ ]
+
+ rl-insert-wrapper: func [
+ [cdecl]
+ count [integer!]
+ key [integer!]
+ return: [integer!]
+ ][
+ rl-insert count key
+ ]
+
+ ]
+]
+
+Windows?: system/platform = 'Windows
+
+read-argument: routine [
+ /local
+ args [str-array!]
+ str [red-string!]
+][
+ if system/args-count <> 2 [
+ SET_RETURN(none-value)
+ exit
+ ]
+ args: system/args-list + 1 ;-- skip binary filename
+ str: simple-io/read-txt args/item
+ SET_RETURN(str)
+]
+
+init-console: routine [
+ str [string!]
+ /local
+ ret
+][
+ #either OS = 'Windows [
+ ;ret: AttachConsole -1
+ ;if zero? ret [print-line "ReadConsole failed!" halt]
+
+ ret: SetConsoleTitle as c-string! string/rs-head str
+ if zero? ret [print-line "SetConsoleTitle failed!" halt]
+ ][
+ rl-bind-key as-integer tab as-integer :rl-insert-wrapper
+ ]
+]
+
+input: routine [
+ prompt [string!]
+ /local
+ len ret str buffer line
+][
+ #either OS = 'Windows [
+ len: 0
+ print as c-string! string/rs-head prompt
+ ret: ReadConsole stdin line-buffer line-buffer-size :len null
+ if zero? ret [print-line "ReadConsole failed!" halt]
+ len: len + 1
+ line-buffer/len: null-byte
+ str: string/load as c-string! line-buffer len
+ ][
+ line: read-line as c-string! string/rs-head prompt
+ if line = null [halt] ; EOF
+
+ #if OS <> 'MacOSX [add-history line]
+
+ str: string/load line 1 + length? line
+; free as byte-ptr! line
+ ]
+ SET_RETURN(str)
+]
+
+count-delimiters: function [
+ buffer [string!]
+ return: [block!]
+][
+ list: copy [0 0]
+ c: none
+
+ foreach c buffer [
+ case [
+ escaped? [
+ escaped?: no
+ ]
+ in-comment? [
+ switch c [
+ #"^/" [in-comment?: no]
+ ]
+ ]
+ 'else [
+ switch c [
+ #"^^" [escaped?: yes]
+ #";" [if zero? list/2 [in-comment?: yes]]
+ #"[" [list/1: list/1 + 1]
+ #"]" [list/1: list/1 - 1]
+ #"{" [list/2: list/2 + 1]
+ #"}" [list/2: list/2 - 1]
+ ]
+ ]
+ ]
+ ]
+ list
+]
+
+do-console: function [][
+ buffer: make string! 10000
+ prompt: red-prompt: "red>> "
+ mode: 'mono
+
+ switch-mode: [
+ mode: case [
+ cnt/1 > 0 ['block]
+ cnt/2 > 0 ['string]
+ 'else [
+ prompt: red-prompt
+ do eval
+ 'mono
+ ]
+ ]
+ prompt: switch mode [
+ block ["[^-"]
+ string ["{^-"]
+ mono [red-prompt]
+ ]
+ ]
+
+ eval: [
+ code: load/all buffer
+
+ unless tail? code [
+ set/any 'result do code
+
+ unless unset? :result [
+ if 67 = length? result: mold/part :result 67 [ ;-- optimized for width = 72
+ clear back tail result
+ append result "..."
+ ]
+ print ["==" result]
+ ]
+ ]
+ clear buffer
+ ]
+
+ while [true][
+ unless tail? line: input prompt [
+ append buffer line
+ cnt: count-delimiters buffer
+
+ either Windows? [
+ remove skip tail buffer -2 ;-- clear extra CR (Windows)
+ ][
+ append buffer lf ;-- Unix
+ ]
+
+ switch mode [
+ block [if cnt/1 <= 0 [do switch-mode]]
+ string [if cnt/2 <= 0 [do switch-mode]]
+ mono [do either any [cnt/1 > 0 cnt/2 > 0][switch-mode][eval]]
+ ]
+ ]
+ ]
+]
+
+q: :quit
+
+if script: read-argument [
+ script: load script
+ either any [
+ script/1 <> 'Red
+ not block? script/2
+ ][
+ print "*** Error: not a Red program!"
+ ][
+ do skip script 2
+ ]
+ quit
+]
+
+init-console "Red Console"
+
+print {
+-=== Red Console alpha version ===-
+(only ASCII input supported)
+}
+
+do-console
\ No newline at end of file diff --git a/tests/examplefiles/example.reds b/tests/examplefiles/example.reds new file mode 100644 index 00000000..eb92310d --- /dev/null +++ b/tests/examplefiles/example.reds @@ -0,0 +1,150 @@ +Red/System [ + Title: "Red/System example file" + Purpose: "Just some code for testing Pygments colorizer" + Language: http://www.red-lang.org/ +] + +#include %../common/FPU-configuration.reds + +; C types + +#define time! long! +#define clock! long! + +date!: alias struct! [ + second [integer!] ; 0-61 (60?) + minute [integer!] ; 0-59 + hour [integer!] ; 0-23 + + day [integer!] ; 1-31 + month [integer!] ; 0-11 + year [integer!] ; Since 1900 + + weekday [integer!] ; 0-6 since Sunday + yearday [integer!] ; 0-365 + daylight-saving-time? [integer!] ; Negative: unknown +] + +#either OS = 'Windows [ + #define clocks-per-second 1000 +][ + ; CLOCKS_PER_SEC value for Syllable, Linux (XSI-conformant systems) + ; TODO: check for other systems + #define clocks-per-second 1000'000 +] + +#import [LIBC-file cdecl [ + + ; Error handling + + form-error: "strerror" [ ; Return error description. + code [integer!] + return: [c-string!] + ] + print-error: "perror" [ ; Print error to standard error output. + string [c-string!] + ] + + + ; Memory management + + make: "calloc" [ ; Allocate zero-filled memory. + chunks [size!] + size [size!] + return: [binary!] + ] + resize: "realloc" [ ; Resize memory allocation. + memory [binary!] + size [size!] + return: [binary!] + ] + ] + + JVM!: alias struct! [ + reserved0 [int-ptr!] + reserved1 [int-ptr!] + reserved2 [int-ptr!] + + DestroyJavaVM [function! [[JNICALL] vm [JVM-ptr!] return: [jint!]]] + AttachCurrentThread [function! [[JNICALL] vm [JVM-ptr!] penv [struct! [p [int-ptr!]]] args [byte-ptr!] return: [jint!]]] + DetachCurrentThread [function! [[JNICALL] vm [JVM-ptr!] return: [jint!]]] + GetEnv [function! [[JNICALL] vm [JVM-ptr!] penv [struct! [p [int-ptr!]]] version [integer!] return: [jint!]]] + AttachCurrentThreadAsDaemon [function! [[JNICALL] vm [JVM-ptr!] penv [struct! [p [int-ptr!]]] args [byte-ptr!] return: [jint!]]] +] + + ;just some datatypes for testing: + + #some-hash + 10-1-2013 + quit + + ;binary: + #{00FF0000} + #{00FF0000 FF000000} + #{00FF0000 FF000000} ;with tab instead of space + 2#{00001111} + 64#{/wAAAA==} + 64#{/wAAA A==} ;with space inside + 64#{/wAAA A==} ;with tab inside + + + ;string with char + {bla ^(ff) foo} + {bla ^(( foo} + ;some numbers: + 12 + 1'000 + 1.2 + FF00FF00h + + ;some tests of hexa number notation with not common ending + [ff00h ff00h] ff00h{} FFh"foo" 00h(1 + 2) (AEh) + +;normal words: +foo char + +;get-word +:foo + +;lit-word: +'foo 'foo + +;multiple comment tests... +1 + 1 +comment "aa" +2 + 2 +comment {aa} +3 + 3 +comment {a^{} +4 + 4 +comment {{}} +5 + 5 +comment { + foo: 6 +} +6 + 6 +comment [foo: 6] +7 + 7 +comment [foo: "[" ] +8 + 8 +comment [foo: {^{} ] +9 + 9 +comment [foo: {boo} ] +10 + 10 +comment 5-May-2014/11:17:34+2:00 +11 + 11 + + +to-integer foo +foo/(a + 1)/b + +call/output reform ['which interpreter] path: copy "" + + version-1.1: 00010001h + + #if type = 'exe [ + push system/stack/frame ;-- save previous frame pointer + system/stack/frame: system/stack/top ;-- @@ reposition frame pointer just after the catch flag +] +push CATCH_ALL ;-- exceptions root barrier +push 0 ;-- keep stack aligned on 64-bit
\ No newline at end of file diff --git a/tests/examplefiles/example.rkt b/tests/examplefiles/example.rkt index a3e4a29e..acc0328e 100644 --- a/tests/examplefiles/example.rkt +++ b/tests/examplefiles/example.rkt @@ -1,5 +1,7 @@ #lang racket +(require (only-in srfi/13 string-contains)) + ; Single-line comment style. ;; Single-line comment style. @@ -8,45 +10,259 @@ #| Multi-line comment style ... +#|### #| nested |#||| |# ... on multiple lines |# -(define (a-function x #:keyword [y 0]) +#;(s-expression comment (one line)) + +#; +(s-expression comment + (multiple lines)) + +#! shebang comment + +#!/shebang comment + +#! shebang \ +comment + +#!/shebang \ +comment + +;; Uncommented numbers after single-line comments +;; NEL
133 +;; LS
8232 +;; PS
8233 + +#reader racket +(define(a-function x #:keyword [y 0]) (define foo0 'symbol) ; () [define foo1 'symbol] ; [] {define foo2 'symbol} ; {} - (and (append (car '(1 2 3)))) + (define 100-Continue 'symbol) + (and (append (car'(1 2 3)))) (regexp-match? #rx"foobar" "foobar") - (regexp-match? #px"foobar" "foobar") - (define a 1)) - (let ([b "foo"]) - (displayln b)) + (regexp-match? #px"\"foo\\(bar\\)?\"" "foobar") + (regexp-match? #rx#"foobar" "foobar") + (regexp-match? #px#"foobar" "foobar") + (define #csa 1) + #Ci (let ([#%A|||b #true C +\|d "foo"]) + (displayln #cS #%\ab\ #true\ C\ +\\d||)) (for/list ([x (in-list (list 1 2 (list 3 4)))]) - (cond - [(pair? x) (car x)] - [else x]))) + (cond + [(pair? x) (car x)] + [else x]))) -;; Literal number examples +;; Literals (values ;; #b - #b1.1 - #b-1.1 - #b1e1 - #b0/1 - #b1/1 - #b1e-1 - #b101 - + #b1 + #b+1 + #b-1 + #b.1 + #b1. + #b0.1 + #b+0.1 + #b-0.1 + #b1/10 + #b+1/10 + #b-1/10 + #b1e11 + #b+1e11 + #b-1e11 + #b.1e11 + #b1.e11 + #b0.1e11 + #b+0.1e11 + #b-0.1e11 + #b1/10e11 + #b+1/10e11 + #b-1/10e11 + #b+i + #b1+i + #b+1+i + #b-1+i + #b.1+i + #b1.+i + #b0.1+i + #b+0.1+i + #b-0.1+i + #b1/10+i + #b+1/10+i + #b-1/10+i + #b1e11+i + #b+1e11+i + #b-1e11+i + #b1.e11+i + #b.1e11+i + #b0.1e11+i + #b+0.1e11+i + #b-0.1e11+i + #b1/10e11+i + #b+1/10e11+i + #b-1/10e11+i + #b+1i + #b1+1i + #b+1+1i + #b-1+1i + #b1.+1i + #b.1+1i + #b0.1+1i + #b+0.1+1i + #b-0.1+1i + #b1/10+1i + #b+1/10+1i + #b-1/10+1i + #b1e11+1i + #b+1e11+1i + #b-1e11+1i + #b.1e11+1i + #b0.1e11+1i + #b+0.1e11+1i + #b-0.1e11+1i + #b1/10e11+1i + #b+1/10e11+1i + #b-1/10e11+1i + #b+1/10e11i + #b1+1/10e11i + #b+1+1/10e11i + #b-1+1/10e11i + #b.1+1/10e11i + #b0.1+1/10e11i + #b+0.1+1/10e11i + #b-0.1+1/10e11i + #b1/10+1/10e11i + #b+1/10+1/10e11i + #b-1/10+1/10e11i + #b1e11+1/10e11i + #b+1e11+1/10e11i + #b-1e11+1/10e11i + #b.1e11+1/10e11i + #b0.1e11+1/10e11i + #b+0.1e11+1/10e11i + #b-0.1e11+1/10e11i + #b1/10e11+1/10e11i + #b+1/10e11+1/10e11i + #b-1/10e11+1/10e11i ;; #d - #d-1.23 - #d1.123 - #d1e3 - #d1e-22 - #d1/2 - #d-1/2 #d1 + #d+1 #d-1 - + #d.1 + #d1. + #d1.2 + #d+1.2 + #d-1.2 + #d1/2 + #d+1/2 + #d-1/2 + #d1e3 + #d+1e3 + #d-1e3 + #d.1e3 + #d1.e3 + #d1.2e3 + #d+1.2e3 + #d-1.2e3 + #d1/2e3 + #d+1/2e3 + #d-1/2e3 + #d+i + #d1+i + #d+1+i + #d-1+i + #d.1+i + #d1.+i + #d1.2+i + #d+1.2+i + #d-1.2+i + #d1/2+i + #d+1/2+i + #d-1/2+i + #d1e3+i + #d+1e3+i + #d-1e3+i + #d1.e3+i + #d.1e3+i + #d1.2e3+i + #d+1.2e3+i + #d-1.2e3+i + #d1/2e3+i + #d+1/2e3+i + #d-1/2e3+i + #d+1i + #d1+1i + #d+1+1i + #d-1+1i + #d1.+1i + #d.1+1i + #d1.2+1i + #d+1.2+1i + #d-1.2+1i + #d1/2+1i + #d+1/2+1i + #d-1/2+1i + #d1e3+1i + #d+1e3+1i + #d-1e3+1i + #d.1e3+1i + #d1.2e3+1i + #d+1.2e3+1i + #d-1.2e3+1i + #d1/2e3+1i + #d+1/2e3+1i + #d-1/2e3+1i + #d+1/2e3i + #d1+1/2e3i + #d+1+1/2e3i + #d-1+1/2e3i + #d.1+1/2e3i + #d1.2+1/2e3i + #d+1.2+1/2e3i + #d-1.2+1/2e3i + #d1/2+1/2e3i + #d+1/2+1/2e3i + #d-1/2+1/2e3i + #d1e3+1/2e3i + #d+1e3+1/2e3i + #d-1e3+1/2e3i + #d.1e3+1/2e3i + #d1.2e3+1/2e3i + #d+1.2e3+1/2e3i + #d-1.2e3+1/2e3i + #d1/2e3+1/2e3i + #d+1/2e3+1/2e3i + #d-1/2e3+1/2e3i + ;; Extflonums + +nan.t + 1t3 + +1t3 + -1t3 + .1t3 + 1.t3 + 1.2t3 + +1.2t3 + -1.2t3 + 1/2t3 + +1/2t3 + -1/2t3 + 1#t0 + 1.#t0 + .2#t0 + 1.2#t0 + 1#/2t0 + 1/2#t0 + 1#/2#t0 + 1#t3 + 1.#t3 + .2#t3 + 1.2#t3 + 1#/2t3 + 1/2#t3 + 1#/2#t3 ;; No # reader prefix -- same as #d -1.23 1.123 @@ -56,7 +272,6 @@ Multi-line comment style ... -1/2 1 -1 - ;; #e #e-1.23 #e1.123 @@ -66,7 +281,24 @@ Multi-line comment style ... #e-1 #e1/2 #e-1/2 - + ;; #d#e + #d#e-1.23 + #d#e1.123 + #d#e1e3 + #d#e1e-22 + #d#e1 + #d#e-1 + #d#e1/2 + #d#e-1/2 + ;; #e#d + #e#d-1.23 + #e#d1.123 + #e#d1e3 + #e#d1e-22 + #e#d1 + #e#d-1 + #e#d1/2 + #e#d-1/2 ;; #i always float #i-1.23 #i1.123 @@ -76,7 +308,126 @@ Multi-line comment style ... #i-1/2 #i1 #i-1 - + ;; Implicitly inexact numbers + +nan.0 + 1# + 1.# + .2# + 1.2# + 1#/2 + 1/2# + 1#/2# + 1#e3 + 1.#e3 + .2#e3 + 1.2#e3 + 1#/2e3 + 1/2#e3 + 1#/2#e3 + +nan.0+i + 1#+i + 1.#+i + .2#+i + 1.2#+i + 1#/2+i + 1/2#+i + 1#/2#+i + 1#e3+i + 1.#e3+i + .2#e3+i + 1.2#e3+i + 1#/2e3+i + 1/2#e3+i + 1#/2#e3+i + +nan.0i + +1#i + +1.#i + +.2#i + +1.2#i + +1#/2i + +1/2#i + +1#/2#i + +1#e3i + +1.#e3i + +.2#e3i + +1.2#e3i + +1#/2e3i + +1/2#e3i + +1#/2#e3i + 0+nan.0i + 0+1#i + 0+1.#i + 0+.2#i + 0+1.2#i + 0+1#/2i + 0+1/2#i + 0+1#/2#i + 0+1#e3i + 0+1.#e3i + 0+.2#e3i + 0+1.2#e3i + 0+1#/2e3i + 0+1/2#e3i + 0+1#/2#e3i + 1#/2#e3+nan.0i + 1#/2#e3+1#i + 1#/2#e3+1.#i + 1#/2#e3+.2#i + 1#/2#e3+1.2#i + 1#/2#e3+1#/2i + 1#/2#e3+1/2#i + 1#/2#e3+1#/2#i + 1#/2#e3+1#e3i + 1#/2#e3+1.#e3i + 1#/2#e3+.2#e3i + 1#/2#e3+1.2#e3i + 1#/2#e3+1#/2e3i + 1#/2#e3+1/2#e3i + 1#/2#e3+1#/2#e3i + +nan.0@1 + 1#@1 + 1.#@1 + .2#@1 + 1.2#@1 + 1#/2@1 + 1/2#@1 + 1#/2#@1 + 1#e3@1 + 1.#e3@1 + .2#e3@1 + 1.2#e3@1 + 1#/2e3@1 + 1/2#e3@1 + 1#/2#e3@1 + 1@+nan.0 + 1@1# + 1@1.# + 1@.2# + 1@1.2# + 1@1#/2 + 1@1/2# + 1@1#/2# + 1@1#e3 + 1@1.#e3 + 1@.2#e3 + 1@1.2#e3 + 1@1#/2e3 + 1@1/2#e3 + 1@1#/2#e3 + 1#/2#e3@1# + 1#/2#e3@1.# + 1#/2#e3@.2# + 1#/2#e3@1.2# + 1#/2#e3@1#/2 + 1#/2#e3@1/2# + 1#/2#e3@1#/2# + 1#/2#e3@1#e3 + 1#/2#e3@1.#e3 + 1#/2#e3@.2#e3 + 1#/2#e3@1.2#e3 + 1#/2#e3@1#/2e3 + 1#/2#e3@1/2#e3 + 1#/2#e3@1#/2#e3 ;; #o #o777.777 #o-777.777 @@ -86,10 +437,307 @@ Multi-line comment style ... #o-3/7 #o777 #o-777 - + #e#o777.777 + #e#o-777.777 + #e#o777e777 + #e#o777e-777 + #e#o3/7 + #e#o-3/7 + #e#o777 + #e#o-777 + #i#o777.777 + #i#o-777.777 + #i#o777e777 + #i#o777e-777 + #i#o3/7 + #i#o-3/7 + #i#o777 + #i#o-777 ;; #x #x-f.f #xf.f + #xfsf + #xfs-f + #x7/f + #x-7/f #x-f #xf + #e#x-f.f + #e#xf.f + #e#xfsf + #e#xfs-f + #e#x7/f + #e#x-7/f + #e#x-f + #e#xf + #i#x-f.f + #i#xf.f + #i#xfsf + #i#xfs-f + #i#x7/f + #i#x-7/f + #i#x-f + #i#xf + ;; Not numbers + '-1.23x + '1.123x + '1e3x + '1e-22x + '1/2x + '-1/2x + '1x + '-1x + '/ + '1/ + '/2 + '1//2 + '1e3. + '1e + 'e3 + '.i + '1.2.3 + '1..2 + '.1. + '@ + '1@ + '@2 + '1@@2 + '1@2@3 + '1@2i + '1+-2i + '1i+2 + '1i+2i + '1+2i+3i + '- + '--1 + '+ + '++1 + '1/2.3 + '1#2 + '1#.2 + '1.#2 + '.#2 + '+nan.t+nan.ti + '+nan.t@nan.t + ;; Booleans + #t + #T + #true + #f + #F + #false + ;; Characters, strings, and byte strings + #\ + #\Null9 + #\n9 + #\99 + #\0009 + #\u3BB + #\u03BB9 + #\U3BB + #\U000003BB9 + #\λ9 + "string\ + \a.\b.\t.\n.\v.\f.\r.\e.\".\'.\\.\1.\123.\1234.\x9.\x30.\x303" + "\u9.\u1234.\u12345.\U9.\U00100000.\U001000000" + #"byte-string\7\xff\t" + #<<HERE STRING +lorem ipsum +dolor sit amet +consectetur HERE STRING +HERE STRING adipisicing elit +HERE STRING + #| +HERE STRING +|# + ;; Other literals + #(vector) + #20() + #s[prefab-structure 1 2 3] + #&{box} + #hash(("a" . 5)) + #hasheq((a . 5) (b . 7)) + #hasheqv((a . 5) (b . 7)) + #'(define x 1) + #`(define x #,pi) + ;; quote, quasiquote, and unquote + 'pi + ' pi + ''pi + '`pi + '`,pi + ',pi + `pi + ` pi + `'pi + ``pi + `,pi + ` , pi + `,'pi + `,`pi + `,`,pi + '(+) + ' (+) + ''(+) + '`(+) + ',(+) + `(+) + ` (+) + `'(+) + ``(+) + `,(+) + ` , (+) + `,'(+) + `,`(+) + `,`,(+) + #readerracket/base'pi.f + '#readerracket/base pi.f + #readerracket/base`pi.f + `#readerracket/base pi.f + #readerracket/base`,pi.f + `#readerracket/base,pi.f + `,#readerracket/base pi.f + #readerracket/base'`,pi.f + '#readerracket/base`,pi.f + '`#readerracket/base,pi.f + '`,#readerracket/base pi.f + #readerracket/base'(*) + '#readerracket/base(*) + #readerracket/base`(*) + `#readerracket/base(*) + #readerracket/base`,(*) + `#readerracket/base,(*) + `,#readerracket/base(*) + #readerracket/base'`,(*) + '#readerracket/base`,(*) + '`#readerracket/base,(*) + '`,#readerracket/base(*) + (quote pi) + (quote (quote pi)) + (quote (quasiquote pi)) + (quote (quasiquote (unquote pi))) + (quote (unquote pi)) + (quasiquote pi) + (quasiquote (quote pi)) + (quasiquote (quasiquote pi)) + (quasiquote (unquote pi)) + (quasiquote (unquote (quote pi))) + (quasiquote (unquote (quasiquote pi))) + (quasiquote (unquote (quasiquote (unquote pi)))) + (quote (+)) + (quote (quote (+))) + (quote (quasiquote (+))) + (quote (unquote (+))) + (quasiquote (+)) + (quasiquote (quote (+))) + (quasiquote (quasiquote (+))) + (quasiquote (unquote (+))) + (quasiquote (unquote (quote (+)))) + (quasiquote (unquote (quasiquote (+)))) + (quasiquote (unquote (quasiquote (unquote (+))))) + #reader racket/base (quote pi.f) + (quote #reader racket/base pi.f) + #reader racket/base (quasiquote pi.f) + (quasiquote #reader racket/base pi.f) + #reader racket/base (quasiquote (unquote pi.f)) + (quasiquote #reader racket/base (unquote pi.f)) + (quasiquote (unquote #reader racket/base pi.f)) + #reader racket/base (quote (quasiquote (unquote pi.f))) + (quote #reader racket/base (quasiquote (unquote pi.f))) + (quote (quasiquote #reader racket/base (unquote pi.f))) + (quote (quasiquote (unquote #reader racket/base pi.f))) + #reader racket/base (quote (*)) + (quote #reader racket/base (*)) + #reader racket/base (quasiquote (*)) + (quasiquote #reader racket/base (*)) + #reader racket/base (quasiquote (unquote (*))) + (quasiquote #reader racket/base (unquote (*))) + (quasiquote (unquote #reader racket/base (*))) + #reader racket/base (quote (quasiquote (unquote (*)))) + (quote #reader racket/base (quasiquote (unquote (*)))) + (quote (quasiquote #reader racket/base (unquote (*)))) + (quote (quasiquote (unquote #reader racket/base (*)))) + ;; Make sure non-identifiers work with quotes + ' "" pi + ' #t pi + ' #() pi + ' #s(s) pi + ' #\u3BB pi + ' #\U000003BB pi + ' #\space pi + ' #\. pi + ' #"" pi + ' #:kw pi + ' #&b pi + ' #'(define x 1) pi + ' #`(define x #,pi) pi + ' #I0 pi + ' #E0 pi + ' #X0 pi + ' #O0 pi + ' #D0 pi + ' #B0 pi + ' #<<EOF +EOF + pi + ' #rx"" pi + ' #rx#"" pi + ' #px"" pi + ' #px#"" pi + ' #hash() pi + ' #hasheq[] pi + ' #hasheqv{} pi + ' #1(v) pi ) + +;; Use the following to generate lists of built-ins and keywords. +;; Run +;; (displayln (wrap-lines KEYWORDS)) +;; (displayln (wrap-lines BUILTINS)) +;; and copy the results into RacketLexer._keywords and RacketLexer._builtins. + +;; (-> (listof string?) string?) +;; Appends all the strings together, quoting them as appropriate for Python, +;; with commas and spaces between them, wrapping at 80 characters, with an +;; indentation of 8 spaces. +(define (wrap-lines lst) + (define INDENTATION '" ") + (define WIDTH '80) + (define (wrap-lines* lst done-lines current-line) + (if (null? lst) + (string-append (foldr string-append "" done-lines) current-line) + (let* ([str (first lst)] + [wrapped-str (if (regexp-match-exact? '#px"[[:ascii:]]+" str) + (string-append "'" str "',") + (string-append "u'" str "',"))] + [new-line (string-append current-line " " wrapped-str)]) + (if ((string-length new-line) . >= . WIDTH) + (wrap-lines* (rest lst) + (append done-lines + `(,(string-append current-line "\n"))) + (string-append INDENTATION wrapped-str)) + (wrap-lines* (rest lst) + done-lines + new-line))))) + (wrap-lines* lst '() INDENTATION)) + +;; (-> string? boolean?) +;; Returns #t if str represents a syntax identifier in the current namespace, +;; otherwise #f. +(define (syntax-identifier? str) + (with-handlers ([exn? exn?]) + (not (eval (call-with-input-string str read))))) + +(define RACKET-NAMESPACE + (parameterize ([current-namespace (make-base-namespace)]) + (namespace-require 'racket) + (current-namespace))) + +(define BOUND-IDENTIFIERS + (parameterize ([current-namespace RACKET-NAMESPACE]) + (sort (map symbol->string (namespace-mapped-symbols)) + string<=?))) + +(define-values (KEYWORDS BUILTINS) + (parameterize ([current-namespace RACKET-NAMESPACE]) + (partition syntax-identifier? BOUND-IDENTIFIERS))) diff --git a/tests/examplefiles/example.sh b/tests/examplefiles/example.sh new file mode 100644 index 00000000..2112cdd1 --- /dev/null +++ b/tests/examplefiles/example.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +printf "%d %s\n" 10 "foo" +printf "%d %s\n" $((10#1)) "bar" + +let "m = 10#${1:1:2}" +echo $m + +m=$((10#${1:4:3} + 10#${1:1:3})) +echo $m + +m=$((10#${1:4:3})) +echo $m + +m=$((10#$1)) +echo $m + +m=$((10#1)) +echo $m + +m=$((10)) +echo $m diff --git a/tests/examplefiles/example.slim b/tests/examplefiles/example.slim new file mode 100644 index 00000000..0e209200 --- /dev/null +++ b/tests/examplefiles/example.slim @@ -0,0 +1,31 @@ +doctype html +html + head + title Slim Examples + meta name="keywords" content="template language" + meta name="author" content=author + javascript: + alert('Slim supports embedded javascript!') + + body + h1 Markup examples + + #content + p This example shows you how a basic Slim file looks like. + + == yield + + - unless items.empty? + table + - for item in items do + tr + td.name = item.name + td.price = item.price + - else + p + | No items found. Please add some inventory. + Thank you! + + div id="footer" + = render 'footer' + | Copyright (C) #{year} #{author} diff --git a/tests/examplefiles/example.sls b/tests/examplefiles/example.sls new file mode 100644 index 00000000..824700e7 --- /dev/null +++ b/tests/examplefiles/example.sls @@ -0,0 +1,51 @@ +include: + - moosefs + +{% for mnt in salt['cmd.run']('ls /dev/data/moose*').split() %} +/mnt/moose{{ mnt[-1] }}: + mount.mounted: + - device: {{ mnt }} + - fstype: xfs + - mkmnt: True + file.directory: + - user: mfs + - group: mfs + - require: + - user: mfs + - group: mfs +{% endfor %} + +/etc/mfshdd.cfg: + file.managed: + - source: salt://moosefs/mfshdd.cfg + - user: root + - group: root + - mode: 644 + - template: jinja + - require: + - pkg: mfs-chunkserver + +/etc/mfschunkserver.cfg: + file.managed: + - source: salt://moosefs/mfschunkserver.cfg + - user: root + - group: root + - mode: 644 + - template: jinja + - require: + - pkg: mfs-chunkserver + +mfs-chunkserver: + pkg: + - installed +mfschunkserver: + service: + - running + - require: +{% for mnt in salt['cmd.run']('ls /dev/data/moose*') %} + - mount: /mnt/moose{{ mnt[-1] }} + - file: /mnt/moose{{ mnt[-1] }} +{% endfor %} + - file: /etc/mfschunkserver.cfg + - file: /etc/mfshdd.cfg + - file: /var/lib/mfs diff --git a/tests/examplefiles/example.stan b/tests/examplefiles/example.stan index e936f54a..69c9ac70 100644 --- a/tests/examplefiles/example.stan +++ b/tests/examplefiles/example.stan @@ -5,6 +5,14 @@ It is not a real model and will not compile */ # also a comment // also a comment +functions { + void f1(void a, real b) { + return 1 / a; + } + real f2(int a, vector b, real c) { + return a + b + c; + } +} data { // valid name int abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_abc; @@ -19,6 +27,8 @@ data { positive_ordered[3] wibble; corr_matrix[3] grault; cov_matrix[3] garply; + cholesky_factor_cov[3] waldo; + cholesky_factor_corr[3] waldo2; real<lower=-1,upper=1> foo1; real<lower=0> foo2; @@ -86,6 +96,7 @@ model { tmp / tmp; tmp .* tmp; tmp ./ tmp; + tmp ^ tmp; ! tmp; - tmp; + tmp; @@ -94,15 +105,18 @@ model { // lp__ should be highlighted // normal_log as a function lp__ <- lp__ + normal_log(plugh, 0, 1); + increment_log_prob(normal_log(plugh, 0, 1)); // print statement and string literal print("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_~@#$%^&*`'-+={}[].,;: "); print("Hello, world!"); print(""); + + // reject statement + reject("I just don't like it"); } generated quantities { real bar1; bar1 <- foo + 1; } - diff --git a/tests/examplefiles/example.thy b/tests/examplefiles/example.thy new file mode 100644 index 00000000..abaa1af8 --- /dev/null +++ b/tests/examplefiles/example.thy @@ -0,0 +1,751 @@ +(* from Isabelle2013-2 src/HOL/Power.thy; BSD license *) + +(* Title: HOL/Power.thy + Author: Lawrence C Paulson, Cambridge University Computer Laboratory + Copyright 1997 University of Cambridge +*) + +header {* Exponentiation *} + +theory Power +imports Num +begin + +subsection {* Powers for Arbitrary Monoids *} + +class power = one + times +begin + +primrec power :: "'a \<Rightarrow> nat \<Rightarrow> 'a" (infixr "^" 80) where + power_0: "a ^ 0 = 1" + | power_Suc: "a ^ Suc n = a * a ^ n" + +notation (latex output) + power ("(_\<^bsup>_\<^esup>)" [1000] 1000) + +notation (HTML output) + power ("(_\<^bsup>_\<^esup>)" [1000] 1000) + +text {* Special syntax for squares. *} + +abbreviation (xsymbols) + power2 :: "'a \<Rightarrow> 'a" ("(_\<^sup>2)" [1000] 999) where + "x\<^sup>2 \<equiv> x ^ 2" + +notation (latex output) + power2 ("(_\<^sup>2)" [1000] 999) + +notation (HTML output) + power2 ("(_\<^sup>2)" [1000] 999) + +end + +context monoid_mult +begin + +subclass power . + +lemma power_one [simp]: + "1 ^ n = 1" + by (induct n) simp_all + +lemma power_one_right [simp]: + "a ^ 1 = a" + by simp + +lemma power_commutes: + "a ^ n * a = a * a ^ n" + by (induct n) (simp_all add: mult_assoc) + +lemma power_Suc2: + "a ^ Suc n = a ^ n * a" + by (simp add: power_commutes) + +lemma power_add: + "a ^ (m + n) = a ^ m * a ^ n" + by (induct m) (simp_all add: algebra_simps) + +lemma power_mult: + "a ^ (m * n) = (a ^ m) ^ n" + by (induct n) (simp_all add: power_add) + +lemma power2_eq_square: "a\<^sup>2 = a * a" + by (simp add: numeral_2_eq_2) + +lemma power3_eq_cube: "a ^ 3 = a * a * a" + by (simp add: numeral_3_eq_3 mult_assoc) + +lemma power_even_eq: + "a ^ (2 * n) = (a ^ n)\<^sup>2" + by (subst mult_commute) (simp add: power_mult) + +lemma power_odd_eq: + "a ^ Suc (2*n) = a * (a ^ n)\<^sup>2" + by (simp add: power_even_eq) + +lemma power_numeral_even: + "z ^ numeral (Num.Bit0 w) = (let w = z ^ (numeral w) in w * w)" + unfolding numeral_Bit0 power_add Let_def .. + +lemma power_numeral_odd: + "z ^ numeral (Num.Bit1 w) = (let w = z ^ (numeral w) in z * w * w)" + unfolding numeral_Bit1 One_nat_def add_Suc_right add_0_right + unfolding power_Suc power_add Let_def mult_assoc .. + +lemma funpow_times_power: + "(times x ^^ f x) = times (x ^ f x)" +proof (induct "f x" arbitrary: f) + case 0 then show ?case by (simp add: fun_eq_iff) +next + case (Suc n) + def g \<equiv> "\<lambda>x. f x - 1" + with Suc have "n = g x" by simp + with Suc have "times x ^^ g x = times (x ^ g x)" by simp + moreover from Suc g_def have "f x = g x + 1" by simp + ultimately show ?case by (simp add: power_add funpow_add fun_eq_iff mult_assoc) +qed + +end + +context comm_monoid_mult +begin + +lemma power_mult_distrib: + "(a * b) ^ n = (a ^ n) * (b ^ n)" + by (induct n) (simp_all add: mult_ac) + +end + +context semiring_numeral +begin + +lemma numeral_sqr: "numeral (Num.sqr k) = numeral k * numeral k" + by (simp only: sqr_conv_mult numeral_mult) + +lemma numeral_pow: "numeral (Num.pow k l) = numeral k ^ numeral l" + by (induct l, simp_all only: numeral_class.numeral.simps pow.simps + numeral_sqr numeral_mult power_add power_one_right) + +lemma power_numeral [simp]: "numeral k ^ numeral l = numeral (Num.pow k l)" + by (rule numeral_pow [symmetric]) + +end + +context semiring_1 +begin + +lemma of_nat_power: + "of_nat (m ^ n) = of_nat m ^ n" + by (induct n) (simp_all add: of_nat_mult) + +lemma power_zero_numeral [simp]: "(0::'a) ^ numeral k = 0" + by (simp add: numeral_eq_Suc) + +lemma zero_power2: "0\<^sup>2 = 0" (* delete? *) + by (rule power_zero_numeral) + +lemma one_power2: "1\<^sup>2 = 1" (* delete? *) + by (rule power_one) + +end + +context comm_semiring_1 +begin + +text {* The divides relation *} + +lemma le_imp_power_dvd: + assumes "m \<le> n" shows "a ^ m dvd a ^ n" +proof + have "a ^ n = a ^ (m + (n - m))" + using `m \<le> n` by simp + also have "\<dots> = a ^ m * a ^ (n - m)" + by (rule power_add) + finally show "a ^ n = a ^ m * a ^ (n - m)" . +qed + +lemma power_le_dvd: + "a ^ n dvd b \<Longrightarrow> m \<le> n \<Longrightarrow> a ^ m dvd b" + by (rule dvd_trans [OF le_imp_power_dvd]) + +lemma dvd_power_same: + "x dvd y \<Longrightarrow> x ^ n dvd y ^ n" + by (induct n) (auto simp add: mult_dvd_mono) + +lemma dvd_power_le: + "x dvd y \<Longrightarrow> m \<ge> n \<Longrightarrow> x ^ n dvd y ^ m" + by (rule power_le_dvd [OF dvd_power_same]) + +lemma dvd_power [simp]: + assumes "n > (0::nat) \<or> x = 1" + shows "x dvd (x ^ n)" +using assms proof + assume "0 < n" + then have "x ^ n = x ^ Suc (n - 1)" by simp + then show "x dvd (x ^ n)" by simp +next + assume "x = 1" + then show "x dvd (x ^ n)" by simp +qed + +end + +context ring_1 +begin + +lemma power_minus: + "(- a) ^ n = (- 1) ^ n * a ^ n" +proof (induct n) + case 0 show ?case by simp +next + case (Suc n) then show ?case + by (simp del: power_Suc add: power_Suc2 mult_assoc) +qed + +lemma power_minus_Bit0: + "(- x) ^ numeral (Num.Bit0 k) = x ^ numeral (Num.Bit0 k)" + by (induct k, simp_all only: numeral_class.numeral.simps power_add + power_one_right mult_minus_left mult_minus_right minus_minus) + +lemma power_minus_Bit1: + "(- x) ^ numeral (Num.Bit1 k) = - (x ^ numeral (Num.Bit1 k))" + by (simp only: eval_nat_numeral(3) power_Suc power_minus_Bit0 mult_minus_left) + +lemma power_neg_numeral_Bit0 [simp]: + "neg_numeral k ^ numeral (Num.Bit0 l) = numeral (Num.pow k (Num.Bit0 l))" + by (simp only: neg_numeral_def power_minus_Bit0 power_numeral) + +lemma power_neg_numeral_Bit1 [simp]: + "neg_numeral k ^ numeral (Num.Bit1 l) = neg_numeral (Num.pow k (Num.Bit1 l))" + by (simp only: neg_numeral_def power_minus_Bit1 power_numeral pow.simps) + +lemma power2_minus [simp]: + "(- a)\<^sup>2 = a\<^sup>2" + by (rule power_minus_Bit0) + +lemma power_minus1_even [simp]: + "-1 ^ (2*n) = 1" +proof (induct n) + case 0 show ?case by simp +next + case (Suc n) then show ?case by (simp add: power_add power2_eq_square) +qed + +lemma power_minus1_odd: + "-1 ^ Suc (2*n) = -1" + by simp + +lemma power_minus_even [simp]: + "(-a) ^ (2*n) = a ^ (2*n)" + by (simp add: power_minus [of a]) + +end + +context ring_1_no_zero_divisors +begin + +lemma field_power_not_zero: + "a \<noteq> 0 \<Longrightarrow> a ^ n \<noteq> 0" + by (induct n) auto + +lemma zero_eq_power2 [simp]: + "a\<^sup>2 = 0 \<longleftrightarrow> a = 0" + unfolding power2_eq_square by simp + +lemma power2_eq_1_iff: + "a\<^sup>2 = 1 \<longleftrightarrow> a = 1 \<or> a = - 1" + unfolding power2_eq_square by (rule square_eq_1_iff) + +end + +context idom +begin + +lemma power2_eq_iff: "x\<^sup>2 = y\<^sup>2 \<longleftrightarrow> x = y \<or> x = - y" + unfolding power2_eq_square by (rule square_eq_iff) + +end + +context division_ring +begin + +text {* FIXME reorient or rename to @{text nonzero_inverse_power} *} +lemma nonzero_power_inverse: + "a \<noteq> 0 \<Longrightarrow> inverse (a ^ n) = (inverse a) ^ n" + by (induct n) + (simp_all add: nonzero_inverse_mult_distrib power_commutes field_power_not_zero) + +end + +context field +begin + +lemma nonzero_power_divide: + "b \<noteq> 0 \<Longrightarrow> (a / b) ^ n = a ^ n / b ^ n" + by (simp add: divide_inverse power_mult_distrib nonzero_power_inverse) + +end + + +subsection {* Exponentiation on ordered types *} + +context linordered_ring (* TODO: move *) +begin + +lemma sum_squares_ge_zero: + "0 \<le> x * x + y * y" + by (intro add_nonneg_nonneg zero_le_square) + +lemma not_sum_squares_lt_zero: + "\<not> x * x + y * y < 0" + by (simp add: not_less sum_squares_ge_zero) + +end + +context linordered_semidom +begin + +lemma zero_less_power [simp]: + "0 < a \<Longrightarrow> 0 < a ^ n" + by (induct n) (simp_all add: mult_pos_pos) + +lemma zero_le_power [simp]: + "0 \<le> a \<Longrightarrow> 0 \<le> a ^ n" + by (induct n) (simp_all add: mult_nonneg_nonneg) + +lemma power_mono: + "a \<le> b \<Longrightarrow> 0 \<le> a \<Longrightarrow> a ^ n \<le> b ^ n" + by (induct n) (auto intro: mult_mono order_trans [of 0 a b]) + +lemma one_le_power [simp]: "1 \<le> a \<Longrightarrow> 1 \<le> a ^ n" + using power_mono [of 1 a n] by simp + +lemma power_le_one: "\<lbrakk>0 \<le> a; a \<le> 1\<rbrakk> \<Longrightarrow> a ^ n \<le> 1" + using power_mono [of a 1 n] by simp + +lemma power_gt1_lemma: + assumes gt1: "1 < a" + shows "1 < a * a ^ n" +proof - + from gt1 have "0 \<le> a" + by (fact order_trans [OF zero_le_one less_imp_le]) + have "1 * 1 < a * 1" using gt1 by simp + also have "\<dots> \<le> a * a ^ n" using gt1 + by (simp only: mult_mono `0 \<le> a` one_le_power order_less_imp_le + zero_le_one order_refl) + finally show ?thesis by simp +qed + +lemma power_gt1: + "1 < a \<Longrightarrow> 1 < a ^ Suc n" + by (simp add: power_gt1_lemma) + +lemma one_less_power [simp]: + "1 < a \<Longrightarrow> 0 < n \<Longrightarrow> 1 < a ^ n" + by (cases n) (simp_all add: power_gt1_lemma) + +lemma power_le_imp_le_exp: + assumes gt1: "1 < a" + shows "a ^ m \<le> a ^ n \<Longrightarrow> m \<le> n" +proof (induct m arbitrary: n) + case 0 + show ?case by simp +next + case (Suc m) + show ?case + proof (cases n) + case 0 + with Suc.prems Suc.hyps have "a * a ^ m \<le> 1" by simp + with gt1 show ?thesis + by (force simp only: power_gt1_lemma + not_less [symmetric]) + next + case (Suc n) + with Suc.prems Suc.hyps show ?thesis + by (force dest: mult_left_le_imp_le + simp add: less_trans [OF zero_less_one gt1]) + qed +qed + +text{*Surely we can strengthen this? It holds for @{text "0<a<1"} too.*} +lemma power_inject_exp [simp]: + "1 < a \<Longrightarrow> a ^ m = a ^ n \<longleftrightarrow> m = n" + by (force simp add: order_antisym power_le_imp_le_exp) + +text{*Can relax the first premise to @{term "0<a"} in the case of the +natural numbers.*} +lemma power_less_imp_less_exp: + "1 < a \<Longrightarrow> a ^ m < a ^ n \<Longrightarrow> m < n" + by (simp add: order_less_le [of m n] less_le [of "a^m" "a^n"] + power_le_imp_le_exp) + +lemma power_strict_mono [rule_format]: + "a < b \<Longrightarrow> 0 \<le> a \<Longrightarrow> 0 < n \<longrightarrow> a ^ n < b ^ n" + by (induct n) + (auto simp add: mult_strict_mono le_less_trans [of 0 a b]) + +text{*Lemma for @{text power_strict_decreasing}*} +lemma power_Suc_less: + "0 < a \<Longrightarrow> a < 1 \<Longrightarrow> a * a ^ n < a ^ n" + by (induct n) + (auto simp add: mult_strict_left_mono) + +lemma power_strict_decreasing [rule_format]: + "n < N \<Longrightarrow> 0 < a \<Longrightarrow> a < 1 \<longrightarrow> a ^ N < a ^ n" +proof (induct N) + case 0 then show ?case by simp +next + case (Suc N) then show ?case + apply (auto simp add: power_Suc_less less_Suc_eq) + apply (subgoal_tac "a * a^N < 1 * a^n") + apply simp + apply (rule mult_strict_mono) apply auto + done +qed + +text{*Proof resembles that of @{text power_strict_decreasing}*} +lemma power_decreasing [rule_format]: + "n \<le> N \<Longrightarrow> 0 \<le> a \<Longrightarrow> a \<le> 1 \<longrightarrow> a ^ N \<le> a ^ n" +proof (induct N) + case 0 then show ?case by simp +next + case (Suc N) then show ?case + apply (auto simp add: le_Suc_eq) + apply (subgoal_tac "a * a^N \<le> 1 * a^n", simp) + apply (rule mult_mono) apply auto + done +qed + +lemma power_Suc_less_one: + "0 < a \<Longrightarrow> a < 1 \<Longrightarrow> a ^ Suc n < 1" + using power_strict_decreasing [of 0 "Suc n" a] by simp + +text{*Proof again resembles that of @{text power_strict_decreasing}*} +lemma power_increasing [rule_format]: + "n \<le> N \<Longrightarrow> 1 \<le> a \<Longrightarrow> a ^ n \<le> a ^ N" +proof (induct N) + case 0 then show ?case by simp +next + case (Suc N) then show ?case + apply (auto simp add: le_Suc_eq) + apply (subgoal_tac "1 * a^n \<le> a * a^N", simp) + apply (rule mult_mono) apply (auto simp add: order_trans [OF zero_le_one]) + done +qed + +text{*Lemma for @{text power_strict_increasing}*} +lemma power_less_power_Suc: + "1 < a \<Longrightarrow> a ^ n < a * a ^ n" + by (induct n) (auto simp add: mult_strict_left_mono less_trans [OF zero_less_one]) + +lemma power_strict_increasing [rule_format]: + "n < N \<Longrightarrow> 1 < a \<longrightarrow> a ^ n < a ^ N" +proof (induct N) + case 0 then show ?case by simp +next + case (Suc N) then show ?case + apply (auto simp add: power_less_power_Suc less_Suc_eq) + apply (subgoal_tac "1 * a^n < a * a^N", simp) + apply (rule mult_strict_mono) apply (auto simp add: less_trans [OF zero_less_one] less_imp_le) + done +qed + +lemma power_increasing_iff [simp]: + "1 < b \<Longrightarrow> b ^ x \<le> b ^ y \<longleftrightarrow> x \<le> y" + by (blast intro: power_le_imp_le_exp power_increasing less_imp_le) + +lemma power_strict_increasing_iff [simp]: + "1 < b \<Longrightarrow> b ^ x < b ^ y \<longleftrightarrow> x < y" +by (blast intro: power_less_imp_less_exp power_strict_increasing) + +lemma power_le_imp_le_base: + assumes le: "a ^ Suc n \<le> b ^ Suc n" + and ynonneg: "0 \<le> b" + shows "a \<le> b" +proof (rule ccontr) + assume "~ a \<le> b" + then have "b < a" by (simp only: linorder_not_le) + then have "b ^ Suc n < a ^ Suc n" + by (simp only: assms power_strict_mono) + from le and this show False + by (simp add: linorder_not_less [symmetric]) +qed + +lemma power_less_imp_less_base: + assumes less: "a ^ n < b ^ n" + assumes nonneg: "0 \<le> b" + shows "a < b" +proof (rule contrapos_pp [OF less]) + assume "~ a < b" + hence "b \<le> a" by (simp only: linorder_not_less) + hence "b ^ n \<le> a ^ n" using nonneg by (rule power_mono) + thus "\<not> a ^ n < b ^ n" by (simp only: linorder_not_less) +qed + +lemma power_inject_base: + "a ^ Suc n = b ^ Suc n \<Longrightarrow> 0 \<le> a \<Longrightarrow> 0 \<le> b \<Longrightarrow> a = b" +by (blast intro: power_le_imp_le_base antisym eq_refl sym) + +lemma power_eq_imp_eq_base: + "a ^ n = b ^ n \<Longrightarrow> 0 \<le> a \<Longrightarrow> 0 \<le> b \<Longrightarrow> 0 < n \<Longrightarrow> a = b" + by (cases n) (simp_all del: power_Suc, rule power_inject_base) + +lemma power2_le_imp_le: + "x\<^sup>2 \<le> y\<^sup>2 \<Longrightarrow> 0 \<le> y \<Longrightarrow> x \<le> y" + unfolding numeral_2_eq_2 by (rule power_le_imp_le_base) + +lemma power2_less_imp_less: + "x\<^sup>2 < y\<^sup>2 \<Longrightarrow> 0 \<le> y \<Longrightarrow> x < y" + by (rule power_less_imp_less_base) + +lemma power2_eq_imp_eq: + "x\<^sup>2 = y\<^sup>2 \<Longrightarrow> 0 \<le> x \<Longrightarrow> 0 \<le> y \<Longrightarrow> x = y" + unfolding numeral_2_eq_2 by (erule (2) power_eq_imp_eq_base) simp + +end + +context linordered_ring_strict +begin + +lemma sum_squares_eq_zero_iff: + "x * x + y * y = 0 \<longleftrightarrow> x = 0 \<and> y = 0" + by (simp add: add_nonneg_eq_0_iff) + +lemma sum_squares_le_zero_iff: + "x * x + y * y \<le> 0 \<longleftrightarrow> x = 0 \<and> y = 0" + by (simp add: le_less not_sum_squares_lt_zero sum_squares_eq_zero_iff) + +lemma sum_squares_gt_zero_iff: + "0 < x * x + y * y \<longleftrightarrow> x \<noteq> 0 \<or> y \<noteq> 0" + by (simp add: not_le [symmetric] sum_squares_le_zero_iff) + +end + +context linordered_idom +begin + +lemma power_abs: + "abs (a ^ n) = abs a ^ n" + by (induct n) (auto simp add: abs_mult) + +lemma abs_power_minus [simp]: + "abs ((-a) ^ n) = abs (a ^ n)" + by (simp add: power_abs) + +lemma zero_less_power_abs_iff [simp, no_atp]: + "0 < abs a ^ n \<longleftrightarrow> a \<noteq> 0 \<or> n = 0" +proof (induct n) + case 0 show ?case by simp +next + case (Suc n) show ?case by (auto simp add: Suc zero_less_mult_iff) +qed + +lemma zero_le_power_abs [simp]: + "0 \<le> abs a ^ n" + by (rule zero_le_power [OF abs_ge_zero]) + +lemma zero_le_power2 [simp]: + "0 \<le> a\<^sup>2" + by (simp add: power2_eq_square) + +lemma zero_less_power2 [simp]: + "0 < a\<^sup>2 \<longleftrightarrow> a \<noteq> 0" + by (force simp add: power2_eq_square zero_less_mult_iff linorder_neq_iff) + +lemma power2_less_0 [simp]: + "\<not> a\<^sup>2 < 0" + by (force simp add: power2_eq_square mult_less_0_iff) + +lemma abs_power2 [simp]: + "abs (a\<^sup>2) = a\<^sup>2" + by (simp add: power2_eq_square abs_mult abs_mult_self) + +lemma power2_abs [simp]: + "(abs a)\<^sup>2 = a\<^sup>2" + by (simp add: power2_eq_square abs_mult_self) + +lemma odd_power_less_zero: + "a < 0 \<Longrightarrow> a ^ Suc (2*n) < 0" +proof (induct n) + case 0 + then show ?case by simp +next + case (Suc n) + have "a ^ Suc (2 * Suc n) = (a*a) * a ^ Suc(2*n)" + by (simp add: mult_ac power_add power2_eq_square) + thus ?case + by (simp del: power_Suc add: Suc mult_less_0_iff mult_neg_neg) +qed + +lemma odd_0_le_power_imp_0_le: + "0 \<le> a ^ Suc (2*n) \<Longrightarrow> 0 \<le> a" + using odd_power_less_zero [of a n] + by (force simp add: linorder_not_less [symmetric]) + +lemma zero_le_even_power'[simp]: + "0 \<le> a ^ (2*n)" +proof (induct n) + case 0 + show ?case by simp +next + case (Suc n) + have "a ^ (2 * Suc n) = (a*a) * a ^ (2*n)" + by (simp add: mult_ac power_add power2_eq_square) + thus ?case + by (simp add: Suc zero_le_mult_iff) +qed + +lemma sum_power2_ge_zero: + "0 \<le> x\<^sup>2 + y\<^sup>2" + by (intro add_nonneg_nonneg zero_le_power2) + +lemma not_sum_power2_lt_zero: + "\<not> x\<^sup>2 + y\<^sup>2 < 0" + unfolding not_less by (rule sum_power2_ge_zero) + +lemma sum_power2_eq_zero_iff: + "x\<^sup>2 + y\<^sup>2 = 0 \<longleftrightarrow> x = 0 \<and> y = 0" + unfolding power2_eq_square by (simp add: add_nonneg_eq_0_iff) + +lemma sum_power2_le_zero_iff: + "x\<^sup>2 + y\<^sup>2 \<le> 0 \<longleftrightarrow> x = 0 \<and> y = 0" + by (simp add: le_less sum_power2_eq_zero_iff not_sum_power2_lt_zero) + +lemma sum_power2_gt_zero_iff: + "0 < x\<^sup>2 + y\<^sup>2 \<longleftrightarrow> x \<noteq> 0 \<or> y \<noteq> 0" + unfolding not_le [symmetric] by (simp add: sum_power2_le_zero_iff) + +end + + +subsection {* Miscellaneous rules *} + +lemma power_eq_if: "p ^ m = (if m=0 then 1 else p * (p ^ (m - 1)))" + unfolding One_nat_def by (cases m) simp_all + +lemma power2_sum: + fixes x y :: "'a::comm_semiring_1" + shows "(x + y)\<^sup>2 = x\<^sup>2 + y\<^sup>2 + 2 * x * y" + by (simp add: algebra_simps power2_eq_square mult_2_right) + +lemma power2_diff: + fixes x y :: "'a::comm_ring_1" + shows "(x - y)\<^sup>2 = x\<^sup>2 + y\<^sup>2 - 2 * x * y" + by (simp add: ring_distribs power2_eq_square mult_2) (rule mult_commute) + +lemma power_0_Suc [simp]: + "(0::'a::{power, semiring_0}) ^ Suc n = 0" + by simp + +text{*It looks plausible as a simprule, but its effect can be strange.*} +lemma power_0_left: + "0 ^ n = (if n = 0 then 1 else (0::'a::{power, semiring_0}))" + by (induct n) simp_all + +lemma power_eq_0_iff [simp]: + "a ^ n = 0 \<longleftrightarrow> + a = (0::'a::{mult_zero,zero_neq_one,no_zero_divisors,power}) \<and> n \<noteq> 0" + by (induct n) + (auto simp add: no_zero_divisors elim: contrapos_pp) + +lemma (in field) power_diff: + assumes nz: "a \<noteq> 0" + shows "n \<le> m \<Longrightarrow> a ^ (m - n) = a ^ m / a ^ n" + by (induct m n rule: diff_induct) (simp_all add: nz field_power_not_zero) + +text{*Perhaps these should be simprules.*} +lemma power_inverse: + fixes a :: "'a::division_ring_inverse_zero" + shows "inverse (a ^ n) = inverse a ^ n" +apply (cases "a = 0") +apply (simp add: power_0_left) +apply (simp add: nonzero_power_inverse) +done (* TODO: reorient or rename to inverse_power *) + +lemma power_one_over: + "1 / (a::'a::{field_inverse_zero, power}) ^ n = (1 / a) ^ n" + by (simp add: divide_inverse) (rule power_inverse) + +lemma power_divide: + "(a / b) ^ n = (a::'a::field_inverse_zero) ^ n / b ^ n" +apply (cases "b = 0") +apply (simp add: power_0_left) +apply (rule nonzero_power_divide) +apply assumption +done + +text {* Simprules for comparisons where common factors can be cancelled. *} + +lemmas zero_compare_simps = + add_strict_increasing add_strict_increasing2 add_increasing + zero_le_mult_iff zero_le_divide_iff + zero_less_mult_iff zero_less_divide_iff + mult_le_0_iff divide_le_0_iff + mult_less_0_iff divide_less_0_iff + zero_le_power2 power2_less_0 + + +subsection {* Exponentiation for the Natural Numbers *} + +lemma nat_one_le_power [simp]: + "Suc 0 \<le> i \<Longrightarrow> Suc 0 \<le> i ^ n" + by (rule one_le_power [of i n, unfolded One_nat_def]) + +lemma nat_zero_less_power_iff [simp]: + "x ^ n > 0 \<longleftrightarrow> x > (0::nat) \<or> n = 0" + by (induct n) auto + +lemma nat_power_eq_Suc_0_iff [simp]: + "x ^ m = Suc 0 \<longleftrightarrow> m = 0 \<or> x = Suc 0" + by (induct m) auto + +lemma power_Suc_0 [simp]: + "Suc 0 ^ n = Suc 0" + by simp + +text{*Valid for the naturals, but what if @{text"0<i<1"}? +Premises cannot be weakened: consider the case where @{term "i=0"}, +@{term "m=1"} and @{term "n=0"}.*} +lemma nat_power_less_imp_less: + assumes nonneg: "0 < (i\<Colon>nat)" + assumes less: "i ^ m < i ^ n" + shows "m < n" +proof (cases "i = 1") + case True with less power_one [where 'a = nat] show ?thesis by simp +next + case False with nonneg have "1 < i" by auto + from power_strict_increasing_iff [OF this] less show ?thesis .. +qed + +lemma power_dvd_imp_le: + "i ^ m dvd i ^ n \<Longrightarrow> (1::nat) < i \<Longrightarrow> m \<le> n" + apply (rule power_le_imp_le_exp, assumption) + apply (erule dvd_imp_le, simp) + done + +lemma power2_nat_le_eq_le: + fixes m n :: nat + shows "m\<^sup>2 \<le> n\<^sup>2 \<longleftrightarrow> m \<le> n" + by (auto intro: power2_le_imp_le power_mono) + +lemma power2_nat_le_imp_le: + fixes m n :: nat + assumes "m\<^sup>2 \<le> n" + shows "m \<le> n" + using assms by (cases m) (simp_all add: power2_eq_square) + + + +subsection {* Code generator tweak *} + +lemma power_power_power [code]: + "power = power.power (1::'a::{power}) (op *)" + unfolding power_def power.power_def .. + +declare power.power.simps [code] + +code_identifier + code_module Power \<rightharpoonup> (SML) Arith and (OCaml) Arith and (Haskell) Arith + +end + diff --git a/tests/examplefiles/example.todotxt b/tests/examplefiles/example.todotxt new file mode 100644 index 00000000..55ee5286 --- /dev/null +++ b/tests/examplefiles/example.todotxt @@ -0,0 +1,9 @@ +(A) Call Mom @Phone +Family +(A) 2014-01-08 Schedule annual checkup +Health +(B) Outline chapter 5 +Novel @Computer +(C) Add cover sheets @Office +TPSReports +Plan backyard herb garden @Home +Pick up milk @GroceryStore +Research self-publishing services +Novel @Computer +x 2014-01-10 Download Todo.txt mobile app @Phone +x 2014-01-10 2014-01-07 Download Todo.txt CLI @Computer diff --git a/tests/examplefiles/example.weechatlog b/tests/examplefiles/example.weechatlog index 9f036166..15e8130f 100644 --- a/tests/examplefiles/example.weechatlog +++ b/tests/examplefiles/example.weechatlog @@ -6,4 +6,6 @@ 2007 Sep 01 00:23:55 -=- Das Topic von &bitlbee lautet: "Welcome to the control channel. Type help for help information." 2007 Sep 01 00:23:55 <root> Welcome to the BitlBee gateway! 2007 Sep 01 00:23:55 <root> -2007 Sep 01 00:23:55 <root> If you've never used BitlBee before, please do read the help information using the help command. Lots of FAQ's are answered there.
\ No newline at end of file +2007 Sep 01 00:23:55 <root> If you've never used BitlBee before, please do read the help information using the help command. Lots of FAQ's are answered there. +# check for fixed pathological matching behavior +1111111111111111111111111111111 diff --git a/tests/examplefiles/exampleScript.cfc b/tests/examplefiles/exampleScript.cfc new file mode 100644 index 00000000..002acbcd --- /dev/null +++ b/tests/examplefiles/exampleScript.cfc @@ -0,0 +1,241 @@ +<cfscript>
+/**
+********************************************************************************
+ContentBox - A Modular Content Platform
+Copyright 2012 by Luis Majano and Ortus Solutions, Corp
+www.gocontentbox.org | www.luismajano.com | www.ortussolutions.com
+********************************************************************************
+Apache License, Version 2.0
+
+Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+********************************************************************************
+* A generic content service for content objects
+*/
+component extends="coldbox.system.orm.hibernate.VirtualEntityService" singleton{
+
+ // DI
+ property name="settingService" inject="id:settingService@cb";
+ property name="cacheBox" inject="cachebox";
+ property name="log" inject="logbox:logger:{this}";
+ property name="customFieldService" inject="customFieldService@cb";
+ property name="categoryService" inject="categoryService@cb";
+ property name="commentService" inject="commentService@cb";
+ property name="contentVersionService" inject="contentVersionService@cb";
+ property name="authorService" inject="authorService@cb";
+ property name="populator" inject="wirebox:populator";
+ property name="systemUtil" inject="SystemUtil@cb";
+
+ /*
+ * Constructor
+ * @entityName.hint The content entity name to bind this service to.
+ */
+ ContentService function init(entityName="cbContent"){
+ // init it
+ super.init(entityName=arguments.entityName, useQueryCaching=true);
+
+ // Test scope coloring in pygments
+ this.colorTestVar = "Just for testing pygments!";
+ cookie.colorTestVar = "";
+ client.colorTestVar = ""
+ session.colorTestVar = "";
+ application.colorTestVar = "";
+
+ return this;
+ }
+
+ /**
+ * Clear all content caches
+ * @async.hint Run it asynchronously or not, defaults to false
+ */
+ function clearAllCaches(boolean async=false){
+ var settings = settingService.getAllSettings(asStruct=true);
+ // Get appropriate cache provider
+ var cache = cacheBox.getCache( settings.cb_content_cacheName );
+ cache.clearByKeySnippet(keySnippet="cb-content",async=arguments.async);
+ return this;
+ }
+
+ /**
+ * Clear all page wrapper caches
+ * @async.hint Run it asynchronously or not, defaults to false
+ */
+ function clearAllPageWrapperCaches(boolean async=false){
+ var settings = settingService.getAllSettings(asStruct=true);
+ // Get appropriate cache provider
+ var cache = cacheBox.getCache( settings.cb_content_cacheName );
+ cache.clearByKeySnippet(keySnippet="cb-content-pagewrapper",async=arguments.async);
+ return this;
+ }
+
+ /**
+ * Clear all page wrapper caches
+ * @slug.hint The slug partial to clean on
+ * @async.hint Run it asynchronously or not, defaults to false
+ */
+ function clearPageWrapperCaches(required any slug, boolean async=false){
+ var settings = settingService.getAllSettings(asStruct=true);
+ // Get appropriate cache provider
+ var cache = cacheBox.getCache( settings.cb_content_cacheName );
+ cache.clearByKeySnippet(keySnippet="cb-content-pagewrapper-#arguments.slug#",async=arguments.async);
+ return this;
+ }
+
+ /**
+ * Clear a page wrapper cache
+ * @slug.hint The slug to clean
+ * @async.hint Run it asynchronously or not, defaults to false
+ */
+ function clearPageWrapper(required any slug, boolean async=false){
+ var settings = settingService.getAllSettings(asStruct=true);
+ // Get appropriate cache provider
+ var cache = cacheBox.getCache( settings.cb_content_cacheName );
+ cache.clear("cb-content-pagewrapper-#arguments.slug#/");
+ return this;
+ }
+
+ /**
+ * Searches published content with cool paramters, remember published content only
+ * @searchTerm.hint The search term to search
+ * @max.hint The maximum number of records to paginate
+ * @offset.hint The offset in the pagination
+ * @asQuery.hint Return as query or array of objects, defaults to array of objects
+ * @sortOrder.hint The sorting of the search results, defaults to publishedDate DESC
+ * @isPublished.hint Search for published, non-published or both content objects [true, false, 'all']
+ * @searchActiveContent.hint Search only content titles or both title and active content. Defaults to both.
+ */
+ function searchContent(
+ any searchTerm="",
+ numeric max=0,
+ numeric offset=0,
+ boolean asQuery=false,
+ any sortOrder="publishedDate DESC",
+ any isPublished=true,
+ boolean searchActiveContent=true){
+
+ var results = {};
+ var c = newCriteria();
+
+ // only published content
+ if( isBoolean( arguments.isPublished ) ){
+ // Published bit
+ c.isEq( "isPublished", javaCast( "Boolean", arguments.isPublished ) );
+ // Published eq true evaluate other params
+ if( arguments.isPublished ){
+ c.isLt("publishedDate", now() )
+ .$or( c.restrictions.isNull("expireDate"), c.restrictions.isGT("expireDate", now() ) )
+ .isEq("passwordProtection","");
+ }
+ }
+
+ // Search Criteria
+ if( len( arguments.searchTerm ) ){
+ // like disjunctions
+ c.createAlias("activeContent","ac");
+ // Do we search title and active content or just title?
+ if( arguments.searchActiveContent ){
+ c.$or( c.restrictions.like("title","%#arguments.searchTerm#%"),
+ c.restrictions.like("ac.content", "%#arguments.searchTerm#%") );
+ }
+ else{
+ c.like( "title", "%#arguments.searchTerm#%" );
+ }
+ }
+
+ // run criteria query and projections count
+ results.count = c.count( "contentID" );
+ results.content = c.resultTransformer( c.DISTINCT_ROOT_ENTITY )
+ .list(offset=arguments.offset, max=arguments.max, sortOrder=arguments.sortOrder, asQuery=arguments.asQuery);
+
+ return results;
+ }
+
+/********************************************* PRIVATE *********************************************/
+
+
+ /**
+ * Update the content hits
+ * @contentID.hint The content id to update
+ */
+ private function syncUpdateHits(required contentID){
+ var q = new Query(sql="UPDATE cb_content SET hits = hits + 1 WHERE contentID = #arguments.contentID#").execute();
+ return this;
+ }
+
+
+ private function closureTest(){
+ methodCall(
+ param1,
+ function( arg1, required arg2 ){
+ var settings = settingService.getAllSettings(asStruct=true);
+ // Get appropriate cache provider
+ var cache = cacheBox.getCache( settings.cb_content_cacheName );
+ cache.clear("cb-content-pagewrapper-#arguments.slug#/");
+ return this;
+ },
+ param1
+ );
+ }
+
+ private function StructliteralTest(){
+ return {
+ foo = bar,
+ brad = 'Wood',
+ func = function( arg1, required arg2 ){
+ var settings = settingService.getAllSettings(asStruct=true);
+ // Get appropriate cache provider
+ var cache = cacheBox.getCache( settings.cb_content_cacheName );
+ cache.clear("cb-content-pagewrapper-#arguments.slug#/");
+ return this;
+ },
+ array = [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 'test',
+ 'testing',
+ 'testerton',
+ {
+ foo = true,
+ brad = false,
+ wood = null
+ }
+ ],
+ last = "final"
+ };
+ }
+
+ private function arrayliteralTest(){
+ return [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 'test',
+ 'testing',
+ 'testerton',
+ {
+ foo = true,
+ brad = false,
+ wood = null
+ },
+ 'testy-von-testavich'
+ ];
+ }
+
+}
+</cfscript>
\ No newline at end of file diff --git a/tests/examplefiles/exampleTag.cfc b/tests/examplefiles/exampleTag.cfc new file mode 100644 index 00000000..753bb826 --- /dev/null +++ b/tests/examplefiles/exampleTag.cfc @@ -0,0 +1,18 @@ +<cfcomponent>
+
+ <cffunction name="init" access="public" returntype="any">
+ <cfargument name="arg1" type="any" required="true">
+ <cfset this.myVariable = arguments.arg1>
+
+ <cfreturn this>
+ </cffunction>
+
+ <cffunction name="testFunc" access="private" returntype="void">
+ <cfargument name="arg1" type="any" required="false">
+
+ <cfif structKeyExists(arguments, "arg1")>
+ <cfset writeoutput("Argument exists")>
+ </cfif>
+ </cffunction>
+
+</cfcomponent>
\ No newline at end of file diff --git a/tests/examplefiles/example_coq.v b/tests/examplefiles/example_coq.v new file mode 100644 index 00000000..fd1a7bc8 --- /dev/null +++ b/tests/examplefiles/example_coq.v @@ -0,0 +1,4 @@ +Lemma FalseLemma : False <-> False. +tauto. +Qed. +Check FalseLemma. diff --git a/tests/examplefiles/example_elixir.ex b/tests/examplefiles/example_elixir.ex index 2e92163d..ddca7f60 100644 --- a/tests/examplefiles/example_elixir.ex +++ b/tests/examplefiles/example_elixir.ex @@ -1,363 +1,233 @@ -# We cannot use to_char_list because it depends on inspect, -# which depends on protocol, which depends on this module. -import Elixir::Builtin, except: [to_char_list: 1] - -defmodule Module do - require Erlang.ets, as: ETS - - @moduledoc """ - This module provides many functions to deal with modules during - compilation time. It allows a developer to dynamically attach - documentation, merge data, register attributes and so forth. - - After the module is compiled, using many of the functions in - this module will raise errors, since it is out of their purpose - to inspect runtime data. Most of the runtime data can be inspected - via the `__info__(attr)` function attached to each compiled module. - """ - - @doc """ - Evalutes the quotes contents in the given module context. - Raises an error if the module was already compiled. - - ## Examples - - defmodule Foo do - contents = quote do: (def sum(a, b), do: a + b) - Module.eval_quoted __MODULE__, contents, [], __FILE__, __LINE__ - end - - Foo.sum(1, 2) #=> 3 - """ - def eval_quoted(module, quoted, binding, filename, line) do - assert_not_compiled!(:eval_quoted, module) - { binding, scope } = Erlang.elixir_module.binding_and_scope_for_eval(line, to_char_list(filename), module, binding) - Erlang.elixir_def.reset_last(module) - Erlang.elixir.eval_quoted([quoted], binding, line, scope) - end - - @doc """ - Checks if the module is compiled or not. - - ## Examples - - defmodule Foo do - Module.compiled?(__MODULE__) #=> false - end - - Module.compiled?(Foo) #=> true - - """ - def compiled?(module) do - table = data_table_for(module) - table == ETS.info(table, :name) - end - - @doc """ - Reads the data for the given module. This is used - to read data of uncompiled modules. If the module - was already compiled, you shoul access the data - directly by invoking `__info__(:data)` in that module. - - ## Examples - - defmodule Foo do - Module.merge_data __MODULE__, value: 1 - Module.read_data __MODULE__ #=> [value: 1] - end - - """ - def read_data(module) do - assert_not_compiled!(:read_data, module) - ETS.lookup_element(data_table_for(module), :data, 2) - end - - @doc """ - Reads the data from `module` at the given key `at`. - - ## Examples - - defmodule Foo do - Module.merge_data __MODULE__, value: 1 - Module.read_data __MODULE__, :value #=> 1 - end - - """ - def read_data(module, at) do - Orddict.get read_data(module), at - end - - @doc """ - Merge the given data into the module, overriding any - previous one. - - If any of the given data is a registered attribute, it is - automatically added to the attribute set, instead of marking - it as data. See register_attribute/2 and add_attribute/3 for - more info. - - ## Examples - - defmodule Foo do - Module.merge_data __MODULE__, value: 1 - end - - Foo.__info__(:data) #=> [value: 1] - - """ - def merge_data(module, data) do - assert_not_compiled!(:merge_data, module) - - table = data_table_for(module) - old = ETS.lookup_element(table, :data, 2) - registered = ETS.lookup_element(table, :registered_attributes, 2) - - { attrs, new } = Enum.partition data, fn({k,_}) -> List.member?(registered, k) end - Enum.each attrs, fn({k,v}) -> add_attribute(module, k, v) end - ETS.insert(table, { :data, Orddict.merge(old, new) }) - end - - @doc """ - Attaches documentation to a given function. It expects - the module the function belongs to, the line (a non negative - integer), the kind (def or defmacro), a tuple representing - the function and its arity and the documentation, which should - be either a binary or a boolean. - - ## Examples - - defmodule MyModule do - Module.add_doc(__MODULE__, __LINE__ + 1, :def, { :version, 0 }, "Manually added docs") - def version, do: 1 - end - - """ - def add_doc(module, line, kind, tuple, doc) when - is_binary(doc) or is_boolean(doc) do - assert_not_compiled!(:add_doc, module) - case kind do - match: :defp - :warn - else: - table = docs_table_for(module) - ETS.insert(table, { tuple, line, kind, doc }) - :ok - end - end +# Numbers +0b0101011 +1234 ; 0x1A ; 0xbeef ; 0763 ; 0o123 +3.14 ; 5.0e21 ; 0.5e-12 +100_000_000 + +# these are not valid numbers +0b012 ; 0xboar ; 0o888 +0B01 ; 0XAF ; 0O123 + +# Characters +?a ; ?1 ; ?\n ; ?\s ; ?\c ; ? ; ?, +?\x{12} ; ?\x{abcd} +?\x34 ; ?\xF + +# these show that only the first digit is part of the character +?\123 ; ?\12 ; ?\7 + +# Atoms +:this ; :that +:'complex atom' +:"with' \"\" 'quotes" +:" multi + line ' \s \123 \xff +atom" +:... ; :<<>> ; :%{} ; :% ; :{} +:++; :--; :*; :~~~; ::: +:% ; :. ; :<- + +# Strings +"Hello world" +"Interspersed \x{ff} codes \7 \8 \65 \016 and \t\s\\s\z\+ \\ escapes" +"Quotes ' inside \" \123 the \"\" \xF \\xF string \\\" end" +"Multiline + string" + +# Char lists +'this is a list' +'escapes \' \t \\\'' +'Multiline + char + list +' + +# Binaries +<<1, 2, 3>> +<<"hello"::binary, c :: utf8, x::[4, unit(2)]>> = "hello™1" + +# Sigils +~r/this + i\s "a" regex/ +~R'this + i\s "a" regex too' +~w(hello #{ ["has" <> "123", '\c\d', "\123 interpol" | []] } world)s +~W(hello #{no "123" \c\d \123 interpol} world)s + +~s{Escapes terminators \{ and \}, but no {balancing} # outside of sigil here } + +~S"No escapes \s\t\n and no #{interpolation}" + +:"atoms work #{"to" <> "o"}" + +# Operators +x = 1 + 2.0 * 3 +y = true and false; z = false or true +... = 144 +... == !x && y || z +"hello" |> String.upcase |> String.downcase() +{^z, a} = {true, x} + +# Free operators (added in 1.0.0) +p ~>> f = bind(p, f) +p1 ~> p2 = pair_right(p1, p2) +p1 <~ p2 = pair_left(p1, p2) +p1 <~> p2 = pair_both(p1, p2) +p |~> f = map(p, f) +p1 <|> p2 = either(p1, p2) + +# Lists, tuples, maps, keywords +[1, :a, 'hello'] ++ [2, 3] +[:head | [?t, ?a, ?i, ?l]] + +{:one, 2.0, "three"} + +[...: "this", <<>>: "is", %{}: "a keyword", %: "list", {}: "too"] +["this is an atom too": 1, "so is this": 2] +[option: "value", key: :word] +[++: "operator", ~~~: :&&&] + +map = %{shortcut: "syntax"} +%{map | "update" => "me"} +%{ 12 => 13, :weird => ['thing'] } + +# Comprehensions +for x <- 1..10, x < 5, do: {x, x} +pixels = "12345678" +for << <<r::4, g::4, b::4, a::size(4)>> <- pixels >> do + [r, {g, %{"b" => a}}] +end + +# String interpolation +"String #{inspect "interpolation"} is quite #{1+4+7} difficult" + +# Identifiers +abc_123 = 1 +_018OP = 2 +A__0 == 3 + +# Modules +defmodule Long.Module.Name do + @moduledoc "Simple module docstring" @doc """ - Checks if a function was defined, regardless if it is - a macro or a private function. Use function_defined?/3 - to assert for an specific type. - - ## Examples - - defmodule Example do - Module.function_defined? __MODULE__, { :version, 0 } #=> false - def version, do: 1 - Module.function_defined? __MODULE__, { :version, 0 } #=> true - end - + Multiline docstring + "with quotes" + and #{ inspect %{"interpolation" => "in" <> "action"} } + now with #{ {:a, 'tuple'} } + and #{ inspect { + :tuple, + %{ with: "nested #{ inspect %{ :interpolation => %{} } }" } + } } """ - def function_defined?(module, tuple) when is_tuple(tuple) do - assert_not_compiled!(:function_defined?, module) - table = function_table_for(module) - ETS.lookup(table, tuple) != [] - end + defstruct [:a, :name, :height] - @doc """ - Checks if a function was defined and also for its `kind`. - `kind` can be either :def, :defp or :defmacro. + @doc ~S''' + No #{interpolation} of any kind. + \000 \x{ff} - ## Examples - - defmodule Example do - Module.function_defined? __MODULE__, { :version, 0 }, :defp #=> false - def version, do: 1 - Module.function_defined? __MODULE__, { :version, 0 }, :defp #=> false - end - - """ - def function_defined?(module, tuple, kind) do - List.member? defined_functions(module, kind), tuple - end - - @doc """ - Return all functions defined in the given module. - - ## Examples - - defmodule Example do - def version, do: 1 - Module.defined_functions __MODULE__ #=> [{:version,1}] - end - - """ - def defined_functions(module) do - assert_not_compiled!(:defined_functions, module) - table = function_table_for(module) - lc { tuple, _, _ } in ETS.tab2list(table), do: tuple - end - - @doc """ - Returns all functions defined in te given module according - to its kind. - - ## Examples - - defmodule Example do - def version, do: 1 - Module.defined_functions __MODULE__, :def #=> [{:version,1}] - Module.defined_functions __MODULE__, :defp #=> [] - end - - """ - def defined_functions(module, kind) do - assert_not_compiled!(:defined_functions, module) - table = function_table_for(module) - entry = kind_to_entry(kind) - ETS.lookup_element(table, entry, 2) - end - - @doc """ - Adds a compilation callback hook that is invoked - exactly before the module is compiled. - - This callback is useful when used with `use` as a mechanism - to clean up any internal data in the module before it is compiled. - - ## Examples - - Imagine you are creating a module/library that is meant for - external usage called `MyLib`. It could be defined as: - - defmodule MyLib do - def __using__(target) do - Module.merge_data target, some_data: true - Module.add_compile_callback(target, __MODULE__, :__callback__) - end - - defmacro __callback__(target) do - value = Orddict.get(Module.read_data(target), :some_data, []) - quote do: (def my_lib_value, do: unquote(value)) - end - end - - And a module could use `MyLib` with: - - defmodule App do - use ModuleTest::ToBeUsed - end - - In the example above, `MyLib` defines a data to the target. This data - can be updated throughout the module definition and therefore, the final - value of the data can only be compiled using a compiation callback, - which will read the final value of :some_data and compile to a function. - """ - def add_compile_callback(module, target, fun // :__compiling__) do - assert_not_compiled!(:add_compile_callback, module) - new = { target, fun } - table = data_table_for(module) - old = ETS.lookup_element(table, :compile_callbacks, 2) - ETS.insert(table, { :compile_callbacks, [new|old] }) - end - - @doc """ - Adds an Erlang attribute to the given module with the given - key and value. The same attribute can be added more than once. - - ## Examples - - defmodule MyModule do - Module.add_attribute __MODULE__, :custom_threshold_for_lib, 10 - end - - """ - def add_attribute(module, key, value) when is_atom(key) do - assert_not_compiled!(:add_attribute, module) - table = data_table_for(module) - attrs = ETS.lookup_element(table, :attributes, 2) - ETS.insert(table, { :attributes, [{key, value}|attrs] }) - end - - @doc """ - Deletes all attributes that matches the given key. - - ## Examples - - defmodule MyModule do - Module.add_attribute __MODULE__, :custom_threshold_for_lib, 10 - Module.delete_attribute __MODULE__, :custom_threshold_for_lib - end - - """ - def delete_attribute(module, key) when is_atom(key) do - assert_not_compiled!(:delete_attribute, module) - table = data_table_for(module) - attrs = ETS.lookup_element(table, :attributes, 2) - final = lc {k,v} in attrs, k != key, do: {k,v} - ETS.insert(table, { :attributes, final }) - end - - @doc """ - Registers an attribute. This allows a developer to use the data API - but Elixir will register the data as an attribute automatically. - By default, `vsn`, `behavior` and other Erlang attributes are - automatically registered. - - ## Examples - - defmodule MyModule do - Module.register_attribute __MODULE__, :custom_threshold_for_lib - @custom_threshold_for_lib 10 - end - - """ - def register_attribute(module, new) do - assert_not_compiled!(:register_attribute, module) - table = data_table_for(module) - old = ETS.lookup_element(table, :registered_attributes, 2) - ETS.insert(table, { :registered_attributes, [new|old] }) - end + \n #{\x{ff}} + ''' + def func(a, b \\ []), do: :ok @doc false - # Used internally to compile documentation. This function - # is private and must be used only internally. - def compile_doc(module, line, kind, pair) do - case read_data(module, :doc) do - match: nil - # We simply discard nil - match: doc - result = add_doc(module, line, kind, pair, doc) - merge_data(module, doc: nil) - result - end + def __before_compile__(_) do + :ok end +end - ## Helpers +# Structs +defmodule Second.Module do + s = %Long.Module.Name{name: "Silly"} + %Long.Module.Name{s | height: {192, :cm}} + ".. #{%Long.Module.Name{s | height: {192, :cm}}} .." +end - defp kind_to_entry(:def), do: :public - defp kind_to_entry(:defp), do: :private - defp kind_to_entry(:defmacro), do: :macros +# Types, pseudo-vars, attributes +defmodule M do + @custom_attr :some_constant - defp to_char_list(list) when is_list(list), do: list - defp to_char_list(bin) when is_binary(bin), do: binary_to_list(bin) + @before_compile Long.Module.Name - defp data_table_for(module) do - list_to_atom Erlang.lists.concat([:d, module]) - end + @typedoc "This is a type" + @type typ :: integer - defp function_table_for(module) do - list_to_atom Erlang.lists.concat([:f, module]) - end - - defp docs_table_for(module) do - list_to_atom Erlang.lists.concat([:o, module]) - end - - defp assert_not_compiled!(fun, module) do - compiled?(module) || - raise ArgumentError, message: - "could not call #{fun} on module #{module} because it was already compiled" - end -end
\ No newline at end of file + @typedoc """ + Another type + """ + @opaque typtyp :: 1..10 + + @spec func(typ, typtyp) :: :ok | :fail + def func(a, b) do + a || b || :ok || :fail + Path.expand("..", __DIR__) + IO.inspect __ENV__ + __NOTAPSEUDOVAR__ = 11 + __MODULE__.func(b, a) + end + + defmacro m() do + __CALLER__ + end +end + +# Functions +anon = fn x, y, z -> + fn(a, b, c) -> + &(x + y - z * a / &1 + b + div(&2, c)) + end +end + +&Set.put(&1, &2) ; & Set.put(&1, &2) ; &( Set.put(&1, &1) ) + +# Function calls +anon.(1, 2, 3); self; hd([1,2,3]) +Kernel.spawn(fn -> :ok end) +IO.ANSI.black + +# Control flow +if :this do + :that +else + :otherwise +end + +pid = self +receive do + {:EXIT, _} -> :done + {^pid, :_} -> nil + after 100 -> :no_luck +end + +case __ENV__.line do + x when is_integer(x) -> x + x when x in 1..12 -> -x +end + +cond do + false -> "too bad" + 4 > 5 -> "oops" + true -> nil +end + +# Lexical scope modifiers +import Kernel, except: [spawn: 1, +: 2, /: 2, Unless: 2] +alias Long.Module.Name, as: N0men123_and4 +use Bitwise + +4 &&& 5 +2 <<< 3 + +# Protocols +defprotocol Useless do + def func1(this) + def func2(that) +end + +defimpl Useless, for: Atom do +end + +# Exceptions +defmodule NotAnError do + defexception [:message] +end + +raise NotAnError, message: "This is not an error" diff --git a/tests/examplefiles/hash_syntax.rb b/tests/examplefiles/hash_syntax.rb new file mode 100644 index 00000000..35b27723 --- /dev/null +++ b/tests/examplefiles/hash_syntax.rb @@ -0,0 +1,5 @@ +{ :old_syntax => 'ok' } +{ 'stings as key' => 'should be ok' } +{ new_syntax: 'broken until now' } +{ withoutunderscore: 'should be ok' } +{ _underscoreinfront: 'might be ok, if I understand the pygments code correct' } diff --git a/tests/examplefiles/hello.at b/tests/examplefiles/hello.at new file mode 100644 index 00000000..23af2f2d --- /dev/null +++ b/tests/examplefiles/hello.at @@ -0,0 +1,6 @@ +def me := object: { + def name := "Kevin"; + def sayHello(peerName) { + system.println(peerName + " says hello!"); + }; +}; diff --git a/tests/examplefiles/hello.golo b/tests/examplefiles/hello.golo new file mode 100644 index 00000000..7e8ca214 --- /dev/null +++ b/tests/examplefiles/hello.golo @@ -0,0 +1,5 @@ +module hello.World + +function main = |args| { + println("Hello world!") +} diff --git a/tests/examplefiles/hello.lsl b/tests/examplefiles/hello.lsl new file mode 100644 index 00000000..61697e7f --- /dev/null +++ b/tests/examplefiles/hello.lsl @@ -0,0 +1,12 @@ +default +{ + state_entry() + { + llSay(0, "Hello, Avatar!"); + } + + touch_start(integer total_number) + { + llSay(0, "Touched."); + } +} diff --git a/tests/examplefiles/File.hy b/tests/examplefiles/hybris_File.hy index 9c86c641..9c86c641 100644 --- a/tests/examplefiles/File.hy +++ b/tests/examplefiles/hybris_File.hy diff --git a/tests/examplefiles/mg_sample.pro b/tests/examplefiles/idl_sample.pro index 814d510d..814d510d 100644 --- a/tests/examplefiles/mg_sample.pro +++ b/tests/examplefiles/idl_sample.pro diff --git a/tests/examplefiles/iex_example b/tests/examplefiles/iex_example new file mode 100644 index 00000000..22407e4e --- /dev/null +++ b/tests/examplefiles/iex_example @@ -0,0 +1,23 @@ +iex> :" multi +...> line ' \s \123 \x20 +...> atom" +:" multi\n line ' S \natom" + +iex(1)> <<"hello"::binary, c :: utf8, x::[4, unit(2)]>> = "hello™1" +"hello™1" + +iex(2)> c +8482 + +iex> 1 + :atom +** (ArithmeticError) bad argument in arithmetic expression + :erlang.+(1, :atom) + +iex(3)> 1 + +...(3)> 2 + +...(3)> 3 +6 + +iex> IO.puts "Hello world" +Hello world +:ok diff --git a/tests/examplefiles/import.hs b/tests/examplefiles/import.hs deleted file mode 100644 index 09058ae6..00000000 --- a/tests/examplefiles/import.hs +++ /dev/null @@ -1,4 +0,0 @@ -import "mtl" Control.Monad.Trans - -main :: IO () -main = putStrLn "hello world" diff --git a/tests/examplefiles/inet_pton6.dg b/tests/examplefiles/inet_pton6.dg index 4104b3e7..3813d5b8 100644 --- a/tests/examplefiles/inet_pton6.dg +++ b/tests/examplefiles/inet_pton6.dg @@ -1,5 +1,5 @@ -re = import! -sys = import! +import '/re' +import '/sys' # IPv6address = hexpart [ ":" IPv4address ] @@ -20,7 +20,7 @@ addrv6 = re.compile $ r'(?i)(?:{})(?::{})?$'.format hexpart addrv4 # # :return: a decimal integer # -base_n = (q digits) -> foldl (x y) -> (x * q + y) 0 digits +base_n = q digits -> foldl (x y -> x * q + y) 0 digits # Parse a sequence of hexadecimal numbers @@ -29,7 +29,7 @@ base_n = (q digits) -> foldl (x y) -> (x * q + y) 0 digits # # :return: an iterable of Python ints # -unhex = q -> q and map p -> (int p 16) (q.split ':') +unhex = q -> q and map (p -> int p 16) (q.split ':') # Parse an IPv6 address as specified in RFC 4291. @@ -39,33 +39,33 @@ unhex = q -> q and map p -> (int p 16) (q.split ':') # :return: an integer which, written in binary form, points to the same node. # inet_pton6 = address -> - raise $ ValueError 'not a valid IPv6 address' if not (match = addrv6.match address) + not (match = addrv6.match address) => raise $ ValueError 'not a valid IPv6 address' start, end, *ipv4 = match.groups! is_ipv4 = not $ None in ipv4 shift = (7 - start.count ':' - 2 * is_ipv4) * 16 - raise $ ValueError 'not a valid IPv6 address' if (end is None and shift) or shift < 0 + (end is None and shift) or shift < 0 => raise $ ValueError 'not a valid IPv6 address' hexaddr = (base_n 0x10000 (unhex start) << shift) + base_n 0x10000 (unhex $ end or '') - (hexaddr << 32) + base_n 0x100 (map int ipv4) if is_ipv4 else hexaddr + if (is_ipv4 => (hexaddr << 32) + base_n 0x100 (map int ipv4)) (otherwise => hexaddr) -inet6_type = q -> switch - not q = 'unspecified' - q == 1 = 'loopback' - (q >> 32) == 0x000000000000ffff = 'IPv4-mapped' - (q >> 64) == 0xfe80000000000000 = 'link-local' - (q >> 120) != 0x00000000000000ff = 'general unicast' - (q >> 112) % (1 << 4) == 0x0000000000000000 = 'multicast w/ reserved scope value' - (q >> 112) % (1 << 4) == 0x000000000000000f = 'multicast w/ reserved scope value' - (q >> 112) % (1 << 4) == 0x0000000000000001 = 'interface-local multicast' - (q >> 112) % (1 << 4) == 0x0000000000000004 = 'admin-local multicast' - (q >> 112) % (1 << 4) == 0x0000000000000005 = 'site-local multicast' - (q >> 112) % (1 << 4) == 0x0000000000000008 = 'organization-local multicast' - (q >> 112) % (1 << 4) == 0x000000000000000e = 'global multicast' - (q >> 112) % (1 << 4) != 0x0000000000000002 = 'multicast w/ unknown scope value' - (q >> 24) % (1 << 112) == 0x00000000000001ff = 'solicited-node multicast' - True = 'link-local multicast' +inet6_type = q -> if + q == 0 => 'unspecified' + q == 1 => 'loopback' + (q >> 32) == 0x000000000000ffff => 'IPv4-mapped' + (q >> 64) == 0xfe80000000000000 => 'link-local' + (q >> 120) != 0x00000000000000ff => 'general unicast' + (q >> 112) % (1 << 4) == 0x0000000000000000 => 'multicast w/ reserved scope value' + (q >> 112) % (1 << 4) == 0x000000000000000f => 'multicast w/ reserved scope value' + (q >> 112) % (1 << 4) == 0x0000000000000001 => 'interface-local multicast' + (q >> 112) % (1 << 4) == 0x0000000000000004 => 'admin-local multicast' + (q >> 112) % (1 << 4) == 0x0000000000000005 => 'site-local multicast' + (q >> 112) % (1 << 4) == 0x0000000000000008 => 'organization-local multicast' + (q >> 112) % (1 << 4) == 0x000000000000000e => 'global multicast' + (q >> 112) % (1 << 4) != 0x0000000000000002 => 'multicast w/ unknown scope value' + (q >> 24) % (1 << 112) == 0x00000000000001ff => 'solicited-node multicast' + otherwise => 'link-local multicast' -print $ (x -> (inet6_type x, hex x)) $ inet_pton6 $ sys.stdin.read!.strip! +print $ (x -> inet6_type x, hex x) $ inet_pton6 $ sys.stdin.read!.strip! diff --git a/tests/examplefiles/interp.scala b/tests/examplefiles/interp.scala new file mode 100644 index 00000000..4131b75e --- /dev/null +++ b/tests/examplefiles/interp.scala @@ -0,0 +1,10 @@ +val n = 123; +val a = s"n=$n"; +val a2 = s"n=$n''"; +val b = s"""n=$n"""; +val c = f"n=$n%f"; +val d = f"""n=$n%f"""; +val d2 = s"""a""""; +val e = s"abc\u00e9"; +val f = s"a${n}b"; +val g = s"a${n + 1}b"; diff --git a/tests/examplefiles/language.hy b/tests/examplefiles/language.hy new file mode 100644 index 00000000..9768c39c --- /dev/null +++ b/tests/examplefiles/language.hy @@ -0,0 +1,165 @@ +;;;; This contains some of the core Hy functions used +;;;; to make functional programming slightly easier. +;;;; + + +(defn _numeric-check [x] + (if (not (numeric? x)) + (raise (TypeError (.format "{0!r} is not a number" x))))) + +(defn cycle [coll] + "Yield an infinite repetition of the items in coll" + (setv seen []) + (for [x coll] + (yield x) + (.append seen x)) + (while seen + (for [x seen] + (yield x)))) + +(defn dec [n] + "Decrement n by 1" + (_numeric-check n) + (- n 1)) + +(defn distinct [coll] + "Return a generator from the original collection with duplicates + removed" + (let [[seen []] [citer (iter coll)]] + (for [val citer] + (if (not_in val seen) + (do + (yield val) + (.append seen val)))))) + +(defn drop [count coll] + "Drop `count` elements from `coll` and yield back the rest" + (let [[citer (iter coll)]] + (try (for [i (range count)] + (next citer)) + (catch [StopIteration])) + citer)) + +(defn even? [n] + "Return true if n is an even number" + (_numeric-check n) + (= (% n 2) 0)) + +(defn filter [pred coll] + "Return all elements from `coll` that pass `pred`" + (let [[citer (iter coll)]] + (for [val citer] + (if (pred val) + (yield val))))) + +(defn inc [n] + "Increment n by 1" + (_numeric-check n) + (+ n 1)) + +(defn instance? [klass x] + (isinstance x klass)) + +(defn iterable? [x] + "Return true if x is iterable" + (try (do (iter x) true) + (catch [Exception] false))) + +(defn iterate [f x] + (setv val x) + (while true + (yield val) + (setv val (f val)))) + +(defn iterator? [x] + "Return true if x is an iterator" + (try (= x (iter x)) + (catch [TypeError] false))) + +(defn neg? [n] + "Return true if n is < 0" + (_numeric-check n) + (< n 0)) + +(defn none? [x] + "Return true if x is None" + (is x None)) + +(defn numeric? [x] + (import numbers) + (instance? numbers.Number x)) + +(defn nth [coll index] + "Return nth item in collection or sequence, counting from 0" + (if (not (neg? index)) + (if (iterable? coll) + (try (first (list (take 1 (drop index coll)))) + (catch [IndexError] None)) + (try (get coll index) + (catch [IndexError] None))) + None)) + +(defn odd? [n] + "Return true if n is an odd number" + (_numeric-check n) + (= (% n 2) 1)) + +(defn pos? [n] + "Return true if n is > 0" + (_numeric_check n) + (> n 0)) + +(defn remove [pred coll] + "Return coll with elements removed that pass `pred`" + (let [[citer (iter coll)]] + (for [val citer] + (if (not (pred val)) + (yield val))))) + +(defn repeat [x &optional n] + "Yield x forever or optionally n times" + (if (none? n) + (setv dispatch (fn [] (while true (yield x)))) + (setv dispatch (fn [] (for [_ (range n)] (yield x))))) + (dispatch)) + +(defn repeatedly [func] + "Yield result of running func repeatedly" + (while true + (yield (func)))) + +(defn take [count coll] + "Take `count` elements from `coll`, or the whole set if the total + number of entries in `coll` is less than `count`." + (let [[citer (iter coll)]] + (for [_ (range count)] + (yield (next citer))))) + +(defn take-nth [n coll] + "Return every nth member of coll + raises ValueError for (not (pos? n))" + (if (pos? n) + (let [[citer (iter coll)] [skip (dec n)]] + (for [val citer] + (yield val) + (for [_ (range skip)] + (next citer)))) + (raise (ValueError "n must be positive")))) + +(defn take-while [pred coll] + "Take all elements while `pred` is true" + (let [[citer (iter coll)]] + (for [val citer] + (if (pred val) + (yield val) + (break))))) + +(defn zero? [n] + "Return true if n is 0" + (_numeric_check n) + (= n 0)) + +(def *exports* ["cycle" "dec" "distinct" "drop" "even?" "filter" "inc" + "instance?" "iterable?" "iterate" "iterator?" "neg?" + "none?" "nth" "numeric?" "odd?" "pos?" "remove" "repeat" + "repeatedly" "take" "take_nth" "take_while" "zero?"]) diff --git a/tests/examplefiles/limbo.b b/tests/examplefiles/limbo.b new file mode 100644 index 00000000..e55a0a62 --- /dev/null +++ b/tests/examplefiles/limbo.b @@ -0,0 +1,456 @@ +implement Ninewin; +include "sys.m"; + sys: Sys; +include "draw.m"; + draw: Draw; + Image, Display, Pointer: import draw; +include "arg.m"; +include "keyboard.m"; +include "tk.m"; +include "wmclient.m"; + wmclient: Wmclient; + Window: import wmclient; +include "sh.m"; + sh: Sh; + +# run a p9 graphics program (default rio) under inferno wm, +# making available to it: +# /dev/winname - naming the current inferno window (changing on resize) +# /dev/mouse - pointer file + resize events; write to change position +# /dev/cursor - change appearance of cursor. +# /dev/draw - inferno draw device +# /dev/cons - read keyboard events, write to 9win stdout. + +Ninewin: module { + init: fn(ctxt: ref Draw->Context, argv: list of string); +}; +winname: string; + +init(ctxt: ref Draw->Context, argv: list of string) +{ + size := Draw->Point(500, 500); + sys = load Sys Sys->PATH; + draw = load Draw Draw->PATH; + wmclient = load Wmclient Wmclient->PATH; + wmclient->init(); + sh = load Sh Sh->PATH; + + buts := Wmclient->Resize; + if(ctxt == nil){ + ctxt = wmclient->makedrawcontext(); + buts = Wmclient->Plain; + } + arg := load Arg Arg->PATH; + arg->init(argv); + arg->setusage("9win [-s] [-x width] [-y height]"); + exportonly := 0; + while(((opt := arg->opt())) != 0){ + case opt { + 's' => + exportonly = 1; + 'x' => + size.x = int arg->earg(); + 'y' => + size.y = int arg->earg(); + * => + arg->usage(); + } + } + if(size.x < 1 || size.y < 1) + arg->usage(); + argv = arg->argv(); + if(argv != nil && hd argv == "-s"){ + exportonly = 1; + argv = tl argv; + } + if(argv == nil && !exportonly) + argv = "rio" :: nil; + if(argv != nil && exportonly){ + sys->fprint(sys->fildes(2), "9win: no command allowed with -s flag\n"); + raise "fail:usage"; + } + title := "9win"; + if(!exportonly) + title += " " + hd argv; + w := wmclient->window(ctxt, title, buts); + w.reshape(((0, 0), size)); + w.onscreen(nil); + if(w.image == nil){ + sys->fprint(sys->fildes(2), "9win: cannot get image to draw on\n"); + raise "fail:no window"; + } + + sys->pctl(Sys->FORKNS|Sys->NEWPGRP, nil); + ld := "/n/9win"; + if(sys->bind("#s", ld, Sys->MREPL) == -1 && + sys->bind("#s", ld = "/n/local", Sys->MREPL) == -1){ + sys->fprint(sys->fildes(2), "9win: cannot bind files: %r\n"); + raise "fail:error"; + } + w.startinput("kbd" :: "ptr" :: nil); + spawn ptrproc(rq := chan of Sys->Rread, ptr := chan[10] of ref Pointer, reshape := chan[1] of int); + + + fwinname := sys->file2chan(ld, "winname"); + fconsctl := sys->file2chan(ld, "consctl"); + fcons := sys->file2chan(ld, "cons"); + fmouse := sys->file2chan(ld, "mouse"); + fcursor := sys->file2chan(ld, "cursor"); + if(!exportonly){ + spawn run(sync := chan of string, w.ctl, ld, argv); + if((e := <-sync) != nil){ + sys->fprint(sys->fildes(2), "9win: %s", e); + raise "fail:error"; + } + } + spawn serveproc(w, rq, fwinname, fconsctl, fcons, fmouse, fcursor); + if(!exportonly){ + # handle events synchronously so that we don't get a "killed" message + # from the shell. + handleevents(w, ptr, reshape); + }else{ + spawn handleevents(w, ptr, reshape); + sys->bind(ld, "/dev", Sys->MBEFORE); + export(sys->fildes(0), w.ctl); + } +} + +handleevents(w: ref Window, ptr: chan of ref Pointer, reshape: chan of int) +{ + for(;;)alt{ + c := <-w.ctxt.ctl or + c = <-w.ctl => + e := w.wmctl(c); + if(e != nil) + sys->fprint(sys->fildes(2), "9win: ctl error: %s\n", e); + if(e == nil && c != nil && c[0] == '!'){ + alt{ + reshape <-= 1 => + ; + * => + ; + } + winname = nil; + } + p := <-w.ctxt.ptr => + if(w.pointer(*p) == 0){ + # XXX would block here if client isn't reading mouse... but we do want to + # extert back-pressure, which conflicts. + alt{ + ptr <-= p => + ; + * => + ; # sys->fprint(sys->fildes(2), "9win: discarding mouse event\n"); + } + } + } +} + +serveproc(w: ref Window, mouserq: chan of Sys->Rread, fwinname, fconsctl, fcons, fmouse, fcursor: ref Sys->FileIO) +{ + winid := 0; + krc: list of Sys->Rread; + ks: string; + + for(;;)alt { + c := <-w.ctxt.kbd => + ks[len ks] = inf2p9key(c); + if(krc != nil){ + hd krc <-= (array of byte ks, nil); + ks = nil; + krc = tl krc; + } + (nil, d, nil, wc) := <-fcons.write => + if(wc != nil){ + sys->write(sys->fildes(1), d, len d); + wc <-= (len d, nil); + } + (nil, nil, nil, rc) := <-fcons.read => + if(rc != nil){ + if(ks != nil){ + rc <-= (array of byte ks, nil); + ks = nil; + }else + krc = rc :: krc; + } + (offset, nil, nil, rc) := <-fwinname.read => + if(rc != nil){ + if(winname == nil){ + winname = sys->sprint("noborder.9win.%d", winid++); + if(w.image.name(winname, 1) == -1){ + sys->fprint(sys->fildes(2), "9win: namewin %q failed: %r", winname); + rc <-= (nil, "namewin failure"); + break; + } + } + d := array of byte winname; + if(offset < len d) + d = d[offset:]; + else + d = nil; + rc <-= (d, nil); + } + (nil, nil, nil, wc) := <-fwinname.write => + if(wc != nil) + wc <-= (-1, "permission denied"); + (nil, nil, nil, rc) := <-fconsctl.read => + if(rc != nil) + rc <-= (nil, "permission denied"); + (nil, d, nil, wc) := <-fconsctl.write => + if(wc != nil){ + if(string d != "rawon") + wc <-= (-1, "cannot change console mode"); + else + wc <-= (len d, nil); + } + (nil, nil, nil, rc) := <-fmouse.read => + if(rc != nil) + mouserq <-= rc; + (nil, d, nil, wc) := <-fmouse.write => + if(wc != nil){ + e := cursorset(w, string d); + if(e == nil) + wc <-= (len d, nil); + else + wc <-= (-1, e); + } + (nil, nil, nil, rc) := <-fcursor.read => + if(rc != nil) + rc <-= (nil, "permission denied"); + (nil, d, nil, wc) := <-fcursor.write => + if(wc != nil){ + e := cursorswitch(w, d); + if(e == nil) + wc <-= (len d, nil); + else + wc <-= (-1, e); + } + } +} + +ptrproc(rq: chan of Sys->Rread, ptr: chan of ref Pointer, reshape: chan of int) +{ + rl: list of Sys->Rread; + c := ref Pointer(0, (0, 0), 0); + for(;;){ + ch: int; + alt{ + p := <-ptr => + ch = 'm'; + c = p; + <-reshape => + ch = 'r'; + rc := <-rq => + rl = rc :: rl; + continue; + } + if(rl == nil) + rl = <-rq :: rl; + hd rl <-= (sys->aprint("%c%11d %11d %11d %11d ", ch, c.xy.x, c.xy.y, c.buttons, c.msec), nil); + rl = tl rl; + } +} + +cursorset(w: ref Window, m: string): string +{ + if(m == nil || m[0] != 'm') + return "invalid mouse message"; + x := int m[1:]; + for(i := 1; i < len m; i++) + if(m[i] == ' '){ + while(m[i] == ' ') + i++; + break; + } + if(i == len m) + return "invalid mouse message"; + y := int m[i:]; + return w.wmctl(sys->sprint("ptr %d %d", x, y)); +} + +cursorswitch(w: ref Window, d: array of byte): string +{ + Hex: con "0123456789abcdef"; + if(len d != 2*4+64) + return w.wmctl("cursor"); + hot := Draw->Point(bglong(d, 0*4), bglong(d, 1*4)); + s := sys->sprint("cursor %d %d 16 32 ", hot.x, hot.y); + for(i := 2*4; i < len d; i++){ + c := int d[i]; + s[len s] = Hex[c >> 4]; + s[len s] = Hex[c & 16rf]; + } + return w.wmctl(s); +} + +run(sync, ctl: chan of string, ld: string, argv: list of string) +{ + Rcmeta: con "|<>&^*[]?();"; + sys->pctl(Sys->FORKNS, nil); + if(sys->bind("#₪", "/srv", Sys->MCREATE) == -1){ + sync <-= sys->sprint("cannot bind srv device: %r"); + exit; + } + srvname := "/srv/9win."+string sys->pctl(0, nil); # XXX do better. + fd := sys->create(srvname, Sys->ORDWR, 8r600); + if(fd == nil){ + sync <-= sys->sprint("cannot create %s: %r", srvname); + exit; + } + sync <-= nil; + spawn export(fd, ctl); + sh->run(nil, "os" :: + "rc" :: "-c" :: + "mount "+srvname+" /mnt/term;"+ + "rm "+srvname+";"+ + "bind -b /mnt/term"+ld+" /dev;"+ + "bind /mnt/term/dev/draw /dev/draw ||"+ + "bind -a /mnt/term/dev /dev;"+ + quotedc("cd"::"/mnt/term"+cwd()::nil, Rcmeta)+";"+ + quotedc(argv, Rcmeta)+";":: + nil + ); +} + +export(fd: ref Sys->FD, ctl: chan of string) +{ + sys->export(fd, "/", Sys->EXPWAIT); + ctl <-= "exit"; +} + +inf2p9key(c: int): int +{ + KF: import Keyboard; + + P9KF: con 16rF000; + Spec: con 16rF800; + Khome: con P9KF|16r0D; + Kup: con P9KF|16r0E; + Kpgup: con P9KF|16r0F; + Kprint: con P9KF|16r10; + Kleft: con P9KF|16r11; + Kright: con P9KF|16r12; + Kdown: con Spec|16r00; + Kview: con Spec|16r00; + Kpgdown: con P9KF|16r13; + Kins: con P9KF|16r14; + Kend: con P9KF|16r18; + Kalt: con P9KF|16r15; + Kshift: con P9KF|16r16; + Kctl: con P9KF|16r17; + + case c { + Keyboard->LShift => + return Kshift; + Keyboard->LCtrl => + return Kctl; + Keyboard->LAlt => + return Kalt; + Keyboard->Home => + return Khome; + Keyboard->End => + return Kend; + Keyboard->Up => + return Kup; + Keyboard->Down => + return Kdown; + Keyboard->Left => + return Kleft; + Keyboard->Right => + return Kright; + Keyboard->Pgup => + return Kpgup; + Keyboard->Pgdown => + return Kpgdown; + Keyboard->Ins => + return Kins; + + # function keys + KF|1 or + KF|2 or + KF|3 or + KF|4 or + KF|5 or + KF|6 or + KF|7 or + KF|8 or + KF|9 or + KF|10 or + KF|11 or + KF|12 => + return (c - KF) + P9KF; + } + return c; +} + +cwd(): string +{ + return sys->fd2path(sys->open(".", Sys->OREAD)); +} + +# from string.b, waiting for declaration to be uncommented. +quotedc(argv: list of string, cl: string): string +{ + s := ""; + while (argv != nil) { + arg := hd argv; + for (i := 0; i < len arg; i++) { + c := arg[i]; + if (c == ' ' || c == '\t' || c == '\n' || c == '\'' || in(c, cl)) + break; + } + if (i < len arg || arg == nil) { + s += "'" + arg[0:i]; + for (; i < len arg; i++) { + if (arg[i] == '\'') + s[len s] = '\''; + s[len s] = arg[i]; + } + s[len s] = '\''; + } else + s += arg; + if (tl argv != nil) + s[len s] = ' '; + argv = tl argv; + } + return s; +} + +in(c: int, s: string): int +{ + n := len s; + if(n == 0) + return 0; + ans := 0; + negate := 0; + if(s[0] == '^') { + negate = 1; + s = s[1:]; + n--; + } + for(i := 0; i < n; i++) { + if(s[i] == '-' && i > 0 && i < n-1) { + if(c >= s[i-1] && c <= s[i+1]) { + ans = 1; + break; + } + i++; + } + else + if(c == s[i]) { + ans = 1; + break; + } + } + if(negate) + ans = !ans; + + # just to showcase labels +skip: + return ans; +} + +bglong(d: array of byte, i: int): int +{ + return int d[i] | (int d[i+1]<<8) | (int d[i+2]<<16) | (int d[i+3]<<24); +} diff --git a/tests/examplefiles/livescript-demo.ls b/tests/examplefiles/livescript-demo.ls index 2ff68c63..03cbcc99 100644 --- a/tests/examplefiles/livescript-demo.ls +++ b/tests/examplefiles/livescript-demo.ls @@ -7,7 +7,9 @@ dashes-identifiers = -> underscores_i$d = -> /regexp1/ //regexp2//g - 'strings' and "strings" and \strings + 'strings' and "strings" and \strings and \#$-"\'strings + +another-word-list = <[ more words ]> [2 til 10] |> map (* 2) diff --git a/tests/examplefiles/main.cmake b/tests/examplefiles/main.cmake index dac3da43..71dc3ce7 100644 --- a/tests/examplefiles/main.cmake +++ b/tests/examplefiles/main.cmake @@ -1,3 +1,5 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6 FATAL_ERROR) + SET( SOURCES back.c io.c main.c ) MESSAGE( ${SOURCES} ) # three arguments, prints "back.cio.cmain.c" MESSAGE( "${SOURCES}" ) # one argument, prints "back.c;io.c;main.c" diff --git a/tests/examplefiles/matlab_sample b/tests/examplefiles/matlab_sample index 4f61afe8..bb00b517 100644 --- a/tests/examplefiles/matlab_sample +++ b/tests/examplefiles/matlab_sample @@ -28,3 +28,7 @@ y = exp(x); {% a block comment %} + +function no_arg_func +fprintf('%s\n', 'function with no args') +end diff --git a/tests/examplefiles/modula2_test_cases.def b/tests/examplefiles/modula2_test_cases.def new file mode 100644 index 00000000..ce86a55b --- /dev/null +++ b/tests/examplefiles/modula2_test_cases.def @@ -0,0 +1,354 @@ +(* Test Cases for Modula-2 Lexer *) + +(* Notes: + (1) Without dialect option nor embedded dialect tag, the lexer operates in + fallback mode, recognising the *combined* literals, punctuation symbols + and operators of all supported dialects, and the *combined* reserved + words and builtins of PIM Modula-2, ISO Modula-2 and Modula-2 R10. + (1) If multiple embedded dialect tags are present, the lexer will use the + first valid tag and ignore any subsequent dialect tags in the file. + (2) An embedded dialect tag overrides any command line dialect option. *) + + +(* Testing command line dialect option *) + +(* for PIM Modula-2 : pygmentize -O full,dialect=m2pim ... + for ISO Modula-2 : pygmentize -O full,dialect=m2iso ... + for Modula-2 R10 : pygmentize -O full,dialect=m2r10 ... + for Objective Modula-2 : pygmentize -O full,dialect=objm2 ... *) + +(* for Aglet extensions : pygmentize -O full,dialect=m2iso+aglet ... + for GNU extensions : pygmentize -O full,dialect=m2pim+gm2 ... + for p1 extensions : pygmentize -O full,dialect=m2iso+p1 ... + for XDS extensions : pygmentize -O full,dialect=m2iso+xds ... + + +(* Testing embedded dialect tags *) + +(* !m2pim*) (* <-- remove whitespace before ! for PIM Modula-2 *) +(* !m2iso*) (* <-- remove whitespace before ! for ISO Modula-2 *) +(* !m2r10*) (* <-- remove whitespace before ! for Modula-2 R10 *) +(* !objm2*) (* <-- remove whitespace before ! for Objective Modula-2 *) + +(* !m2iso+aglet*) (* <-- remove whitespace before ! for Aglet extensions *) +(* !m2pim+gm2*) (* <-- remove whitespace before ! for GNU extensions *) +(* !m2iso+p1*) (* <-- remove whitespace before ! for p1 extensions *) +(* !m2iso+xds*) (* <-- remove whitespace before ! for XDS extensions *) + + +(* Dialect Indicating Names *) + +(* recognised names should be highlighted *) + +QUALIFIED (* PIM and ISO *) + +PACKEDSET (* ISO only *) + +ARGLIST (* M2 R10 and ObjM2 *) + +BYCOPY (* ObjM2 only *) + +BITSET8 (* Aglet, GNU and M2 R10 *) + +__FILE__ (* GNU only *) + +BCD (* p1 and M2 R10 *) + +SEQ (* XDS only *) + + +(* Literal Tests *) + +(* recognised literals should be rendered as one unit + unrecognised literals should be rendered as error *) + +ch := 'a'; ch := "a"; (* all dialects *) +ch := 0u20; unich := 0u2038 (* M2 R10 *) + +s := 'The cat said "meow!".'; +s := "It is eight O'clock."; + + +n := 123; n = 1000000; (* all dialects *) +n := 123; n = 1'000'000; (* M2 R10 *) + +n := 0b0110; n:= 0b0110'1100'0111; (* M2 R10 *) +n := 0xFF00; n:= 0xDEAD'BEEF'0F00; (* M2 R10 *) + +r := 1.23; r := 1000000.000001; (* all dialects *) +r := 1.23; r := 1'000'000.000'001; (* M2 R10 *) + +r := 1.234E6; r:= 1.234E-6; r := 1.234567E1000; (* PIM + ISO *) +r := 1.234e6; r:= 1.234e-6; r := 1.234'567e1'000; (* M2 R10 *) + +ch := 0377C; n := 0377B; n := 07FF0H; (* ISO + PIM *) + + +(* Non-Alphabetic Operator Tests *) + +(* supported operators should be rendered as one unit + unsupported operators should be rendered as errors *) + +a := b + c - d * e / f; (* all dialects *) + +SetDiff := A \ B; (* M2 R10 *) + +dotProduct := v1 *. v2; catArray := array1 +> array2; (* M2 R10 *) + +bool := a = b; bool := a > b; bool := a < b; +bool := a # b; bool := a >= b; bool := a <= b; + +bool := a <> b; (* PIM + ISO *) + +bool := a == b; (* M2 R10 *) + +(*&*) IF a & b THEN ... END; (* PIM + ISO *) + +(*~*) IF ~ b THEN ... END; (* PIM + ISO *) + +(*::*) int := real :: INTEGER; (* M2 R10 *) + +(*++*) FOR i++ IN range DO ... END; (* M2 R10 *) +(*--*) FOR i-- IN range DO ... END; (* M2 R10 *) + +(*^*) next := this^.next; (* all dialects *) +(*@*) next := this@.next; (* ISO *) + +(*`*) str := `NSString alloc init; (* ObjM2 *) + + +(* Punctuation Tests *) + +(* supported punctuation should be rendered as one unit + unsupported punctuation should be rendered as an error *) + +(*.*) Foo.Bar.Baz; (*..*) TYPE Sign = [-1..1] OF INTEGER; + +(*|:*) CASE foo OF | 1 : bar | 2 : bam | 3 : boo END; +(*!:*) CASE foo OF 1 : bar ! 2 : bam ! 3 : boo END; (* ISO *) + +(*[]()*) array[n] := foo(); + +(*{}*) CONST Bar = { 1, 2, 3 }; + +(*?*) TPROPERTIES = isCollection, isIndexed | isRigid?; (* M2 R10 *) + +(*~*) CONST ~ isFoobar = Foo AND Bar; (* M2 R10 *) +(*->*) isFoobar -> PROCEDURE [ABS]; (* M2 R10 *) + +(*<<>>*) GENLIB Foo FROM Template FOR Bar = <<ARRAY OF CHAR>> END; (* M2 R10 *) + + +(* Single Line Comment Test *) + +(* should be rendered as comment if supported, as error if unsupported *) + +// This is a single line comment (M2 R10 + ObjM2) + + +(* Pragma Delimiter Tests *) + +(* PIM style pragma should be rendered as pragma in PIM dialects, + as multiline comment in all other dialects. *) + +(*$INLINE*) (* PIM *) + +(* ISO style pragma should be rendered as error in PIM dialects, + as pragma in all other dialects. *) + +<*INLINE*> (* all other dialects *) + + +(* Operator Substitution Test When in Algol mode *) + +IF foo # bar THEN ... END; (* # should be rendered as not equal symbol *) + +IF foo >= bar THEN ... END; (* >= should be rendered as not less symbol *) + +IF foo <= bar THEN ... END; (* <= should be rendered as not greater symbol *) + +IF foo == bar THEN ... END; (* == should be rendered as identity symbol *) + +dotProduct := v1 *. v2; (* *. should be rendered as dot product symbol *) + + +(* Reserved Words and Builtins Test *) + +(* supported reserved words and builtins should be highlighted *) + +(* reserved words common to all dialects *) + +AND ARRAY BEGIN BY CASE CONST DEFINITION DIV DO ELSE ELSIF END EXIT FOR FROM +IF IMPLEMENTATION IMPORT IN LOOP MOD MODULE NOT OF OR POINTER PROCEDURE +RECORD REPEAT RETURN SET THEN TO TYPE UNTIL VAR WHILE + +(* builtins common to all dialects *) + +ABS BOOLEAN CARDINAL CHAR CHR FALSE INTEGER LONGINT LONGREAL +MAX MIN NIL ODD ORD REAL TRUE + +(* pseudo builtins common to all dialects *) + +ADDRESS BYTE WORD ADR + + +(* additional reserved words for PIM *) + +EXPORT QUALIFIED WITH + +(* additional builtins for PIM *) + +BITSET CAP DEC DISPOSE EXCL FLOAT HALT HIGH INC INCL NEW NIL PROC SIZE TRUNC VAL + +(* additional pseudo-builtins for PIM *) + +SYSTEM PROCESS TSIZE NEWPROCESS TRANSFER + + +(* additional reserved words for ISO 10514-1 *) + +EXCEPT EXPORT FINALLY FORWARD PACKEDSET QUALIFIED REM RETRY WITH + +(* additional reserved words for ISO 10514-2 & ISO 10514-3 *) + +ABSTRACT AS CLASS GUARD INHERIT OVERRIDE READONLY REVEAL TRACED UNSAFEGUARDED + +(* additional builtins for ISO 10514-1 *) + +BITSET CAP CMPLX COMPLEX DEC DISPOSE EXCL FLOAT HALT HIGH IM INC INCL INT +INTERRUPTIBLE LENGTH LFLOAT LONGCOMPLEX NEW PROC PROTECTION RE SIZE TRUNC +UNINTERRUBTIBLE VAL + +(* additional builtins for ISO 10514-2 & ISO 10514-3 *) + +CREATE DESTROY EMPTY ISMEMBER SELF + + +(* additional pseudo-builtins for ISO *) + +(* SYSTEM *) +SYSTEM BITSPERLOC LOCSPERBYTE LOCSPERWORD LOC ADDADR SUBADR DIFADR MAKEADR +ADR ROTATE SHIFT CAST TSIZE + +(* COROUTINES *) +COROUTINES ATTACH COROUTINE CURRENT DETACH HANDLER INTERRUPTSOURCE IOTRANSFER +IsATTACHED LISTEN NEWCOROUTINE PROT TRANSFER + +(* EXCEPTIONS *) +EXCEPTIONS AllocateSource CurrentNumber ExceptionNumber ExceptionSource +GetMessage IsCurrentSource IsExceptionalExecution RAISE + +(* TERMINATION *) +TERMINATION IsTerminating HasHalted + +(* M2EXCEPTION *) +M2EXCEPTION M2Exceptions M2Exception IsM2Exception indexException rangeException +caseSelectException invalidLocation functionException wholeValueException +wholeDivException realValueException realDivException complexValueException +complexDivException protException sysException coException exException + + +(* additional reserved words for M2 R10 *) + +ALIAS ARGLIST BLUEPRINT COPY GENLIB INDETERMINATE NEW NONE OPAQUE REFERENTIAL +RELEASE RETAIN + +(* with symbolic assembler language extension *) +ASM REG + +(* additional builtins for M2 R10 *) + +CARDINAL COUNT EMPTY EXISTS INSERT LENGTH LONGCARD OCTET PTR PRED READ READNEW +REMOVE RETRIEVE SORT STORE SUBSET SUCC TLIMIT TMAX TMIN TRUE TSIZE UNICHAR +WRITE WRITEF + +(* additional pseudo-builtins for M2 R10 *) + +(* TPROPERTIES *) +TPROPERTIES PROPERTY LITERAL TPROPERTY TLITERAL TBUILTIN TDYN TREFC TNIL +TBASE TPRECISION TMAXEXP TMINEXP + +(* CONVERSION *) +CONVERSION TSXFSIZE SXF VAL + +(* UNSAFE *) +UNSAFE CAST INTRINSIC AVAIL ADD SUB ADDC SUBC FETCHADD FETCHSUB SHL SHR ASHR +ROTL ROTR ROTLC ROTRC BWNOT BWAND BWOR BWXOR BWNAND BWNOR SETBIT TESTBIT +LSBIT MSBIT CSBITS BAIL HALT TODO FFI ADDR VARGLIST VARGC + +(* ATOMIC *) +ATOMIC INTRINSIC AVAIL SWAP CAS INC DEC BWAND BWNAND BWOR BWXOR + +(* COMPILER *) +COMPILER DEBUG MODNAME PROCNAME LINENUM DEFAULT HASH + +(* ASSEMBLER *) +ASSEMBLER REGISTER SETREG GETREG CODE + + +(* standard library ADT identifiers for M2 R10 *) + +(* rendered as builtins when dialect is set to Modula-2 R10, + this can be turned off by option treat_stdlib_adts_as_builtins=off *) +BCD LONGBCD BITSET SHORTBITSET LONGBITSET LONGLONGBITSET COMPLEX LONGCOMPLEX +SHORTCARD LONGLONGCARD SHORTINT LONGLONGINT POSINT SHORTPOSINT LONGPOSINT +LONGLONGPOSINT BITSET8 BITSET16 BITSET32 BITSET64 BITSET128 BS8 BS16 BS32 +BS64 BS128 CARDINAL8 CARDINAL16 CARDINAL32 CARDINAL64 CARDINAL128 CARD8 +CARD16 CARD32 CARD64 CARD128 INTEGER8 INTEGER16 INTEGER32 INTEGER64 +INTEGER128 INT8 INT16 INT32 INT64 INT128 STRING UNISTRING + + +(* additional reserved words for ObjM2 *) + +(* Note: ObjM2 is a superset of M2 R10 *) + +BYCOPY BYREF CLASS CONTINUE CRITICAL INOUT METHOD ON OPTIONAL OUT PRIVATE +PROTECTED PROTOCOL PUBLIC SUPER TRY + +(* additional builtins for ObjM2 *) + +OBJECT NO YES + + +(* additional builtins for Aglet Extensions to ISO *) + +BITSET8 BITSET16 BITSET32 CARDINAL8 CARDINAL16 CARDINAL32 INTEGER8 INTEGER16 +INTEGER32 + + +(* additional reserved words for GNU Extensions to PIM *) + +ASM __ATTRIBUTE__ __BUILTIN__ __COLUMN__ __DATE__ __FILE__ __FUNCTION__ +__LINE__ __MODULE__ VOLATILE + +(* additional builtins for GNU Extensions to PIM *) + +BITSET8 BITSET16 BITSET32 CARDINAL8 CARDINAL16 CARDINAL32 CARDINAL64 COMPLEX32 +COMPLEX64 COMPLEX96 COMPLEX128 INTEGER8 INTEGER16 INTEGER32 INTEGER64 REAL8 +REAL16 REAL32 REAL96 REAL128 THROW + + +(* additional pseudo-builtins for p1 Extensions to ISO *) + +BCD + + +(* additional reserved words for XDS Extensions to ISO *) + +SEQ + +(* additional builtins for XDS Extensions to ISO *) + +ASH ASSERT DIFFADR_TYPE ENTIER INDEX LEN LONGCARD SHORTCARD SHORTINT + +(* additional pseudo-builtins for XDS Extensions to ISO *) + +(* SYSTEM *) +PROCESS NEWPROCESS BOOL8 BOOL16 BOOL32 CARD8 CARD16 CARD32 INT8 INT16 INT32 +REF MOVE FILL GET PUT CC int unsigned size_t void + +(* COMPILER *) +COMPILER OPTION EQUATION + + +(* end of file *)
\ No newline at end of file diff --git a/tests/examplefiles/objc_example.m b/tests/examplefiles/objc_example.m index 67b33022..f3f85f65 100644 --- a/tests/examplefiles/objc_example.m +++ b/tests/examplefiles/objc_example.m @@ -1,32 +1,179 @@ -#import "Somefile.h" +// Test various types of includes +#import <Foundation/Foundation.h> +# import <AppKit/AppKit.h> +#import "stdio.h" +#\ + import \ + "stdlib.h" +# /*line1*/ \ +import /* line 2 */ \ +"stdlib.h" // line 3 -@implementation ABC +// Commented out code with preprocessor +#if 0 +#define MY_NUMBER 3 +#endif -- (id)a:(B)b { - return 1; + #\ + if 1 +#define TEST_NUMBER 3 +#endif + +// Empty preprocessor +# + +// Class forward declaration +@class MyClass; + +// Empty classes +@interface EmptyClass +@end +@interface EmptyClass2 +{ +} +@end +@interface EmptyClass3 : EmptyClass2 +{ +} +@end + +// Custom class inheriting from built-in +@interface MyClass : NSObject +{ +@public + NSString *myString; + __weak NSString *_weakString; +@protected + NSTextField *_textField; +@private + NSDate *privateDate; } +// Various property aatributes +@property(copy, readwrite, nonatomic) NSString *myString; +@property(weak) NSString *weakString; +@property(retain, strong, atomic) IBOutlet NSTextField *textField; + +// Class methods ++ (void)classMethod1:(NSString *)arg; ++ (void)classMethod2:(NSString *) arg; // Test space before arg + @end -@implementation ABC +typedef id B; -- (void)xyz; +#pragma mark MyMarker +// MyClass.m +// Class extension to declare private property +@interface MyClass () +@property(retain) NSDate *privateDate; +- (void)hiddenMethod; @end -NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys: - @"quattuor", @"four", @"quinque", @"five", @"sex", @"six", nil]; +// Special category +@interface MyClass (Special) +@property(retain) NSDate *specialDate; +@end + +@implementation MyClass +@synthesize myString; +@synthesize privateDate; + +- (id)a:(B)b { + /** + * C-style comment + */ + + // Selector keywords/types + SEL someMethod = @selector(hiddenMethod); + + // Boolean types + Boolean b1 = FALSE; + BOOL b2 = NO; + bool b3 = true; + /** + * Number literals + */ + // Int Literal + NSNumber *n1 = @( 1 ); + // Method call + NSNumber *n2 = @( [b length] ); + // Define variable + NSNumber *n3 = @( TEST_NUMBER ); + // Arthimetic expression + NSNumber *n4 = @(1 + 2); + // From variable + int myInt = 5; + NSNumber *n5 = @(myInt); + // Nest expression + NSNumber *n6 = @(1 + (2 + 6.0)); + // Bool literal + NSNumber *n7 = @NO; + // Bool expression + NSNumber *n8 = @(YES); + // Character + NSNumber *n9 = @'a'; + // int + NSNumber *n10 = @123; + // unsigned + NSNumber *n11 = @1234U; + // long + NSNumber *n12 = @1234567890L; + // float + NSNumber *n13 = @3.14F; + // double + NSNumber *n14 = @3.14F; + + // Array literals + NSArray *arr = @[ @"1", @"2" ]; + arr = @[ @[ @"1", @"2" ], [arr lastObject] ]; + [arr lastObject]; + [@[ @"1", @"2" ] lastObject]; + + // Dictionary literals + NSDictionary *d = @{ @"key": @"value" }; + [[d allKeys] lastObject]; + [[@{ @"key": @"value" } allKeys] lastObject]; + d = @{ @"key": @{ @"key": @"value" } }; -NSString *key; -for (key in dictionary) { - NSLog(@"English: %@, Latin: %@", key, [dictionary valueForKey:key]); + [self hiddenMethod]; + [b length]; + [privateDate class]; + + NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys: + @"1", @"one", @"2", @"two", @"3", @"three", nil]; + + NSString *key; + for (key in dictionary) { + NSLog(@"Number: %@, Word: %@", key, [dictionary valueForKey:key]); + } + + // Blocks + int (^myBlock)(int arg1, int arg2); + NSString *(^myName)(NSString *) = ^(NSString *value) { + return value; + }; + + return nil; } -// Literals -NSArray *a = @[ @"1", @"2" ]; +- (void)hiddenMethod { + // Synchronized block + @synchronized(self) { + [myString retain]; + [myString release]; + } +} -NSDictionary *d = @{ @"key": @"value" }; ++ (void)classMethod1:(NSString *)arg {} ++ (void)classMethod2:(NSString *) arg +{ + // Autorelease pool block + @autoreleasepool { + NSLog(@"Hello, World!"); + } +} -NSNumber *n1 = @( 1 ); -NSNumber *n2 = @( [a length] ); +@end diff --git a/tests/examplefiles/objc_example2.m b/tests/examplefiles/objc_example2.m deleted file mode 100644 index 8cd9b060..00000000 --- a/tests/examplefiles/objc_example2.m +++ /dev/null @@ -1,24 +0,0 @@ -// MyClass.h -@interface MyClass : NSObject -{ - NSString *value; - NSTextField *textField; -@private - NSDate *lastModifiedDate; -} -@property(copy, readwrite) NSString *value; -@property(retain) IBOutlet NSTextField *textField; -@end - -// MyClass.m -// Class extension to declare private property -@interface MyClass () -@property(retain) NSDate *lastModifiedDate; -@end - -@implementation MyClass -@synthesize value; -@synthesize textField; -@synthesize lastModifiedDate; -// implementation continues -@end diff --git a/tests/examplefiles/example.p b/tests/examplefiles/openedge_example index e8c17e33..e8c17e33 100644 --- a/tests/examplefiles/example.p +++ b/tests/examplefiles/openedge_example diff --git a/tests/examplefiles/pawn_example b/tests/examplefiles/pawn_example new file mode 100644 index 00000000..ee2ecca2 --- /dev/null +++ b/tests/examplefiles/pawn_example @@ -0,0 +1,25 @@ +{include.i} +{nested.i {include.i}} + +&SCOPED-DEFINE MY_NAME "Abe" + +DEF VAR i AS INT NO-UNDO. +i = 0xABE + 1337 / (1 * 1.00) + +def var clowercasetest as char no-undo. +DEF VAR vardashtest AS DATETIME-TZ NO-UNDO. + +DEFINE TEMP-TABLE ttNames NO-UNDO + FIELD cName AS CHAR + INDEX IXPK_ttNames IS PRIMARY UNIQUE cName. + +/* One-line comment */ +/* Two-line + Comment */ + +CREATE ttNames. +ASSIGN ttNames.cName = {&MY_NAME}. + +FOR EACH ttNames: + MESSAGE "Hello, " + ttNames.cName + '!' VIEW-AS ALERT-BOX. +END. diff --git a/tests/examplefiles/pycon_test.pycon b/tests/examplefiles/pycon_test.pycon index ff702864..9c4fc3d3 100644 --- a/tests/examplefiles/pycon_test.pycon +++ b/tests/examplefiles/pycon_test.pycon @@ -9,6 +9,9 @@ KeyboardInterrupt >>> 1/0 Traceback (most recent call last): -... + ... ZeroDivisionError +>>> 1/0 # this used to swallow the traceback +Traceback (most recent call last): + ... diff --git a/tests/examplefiles/qbasic_example b/tests/examplefiles/qbasic_example new file mode 100644 index 00000000..27041af6 --- /dev/null +++ b/tests/examplefiles/qbasic_example @@ -0,0 +1,2 @@ +10 print RIGHT$("hi there", 5) +20 goto 10 diff --git a/tests/examplefiles/r6rs-comments.scm b/tests/examplefiles/r6rs-comments.scm new file mode 100644 index 00000000..cd5c3636 --- /dev/null +++ b/tests/examplefiles/r6rs-comments.scm @@ -0,0 +1,23 @@ +#!r6rs + +#| + + The FACT procedure computes the factorial + + of a non-negative integer. + +|# + +(define fact + + (lambda (n) + + ;; base case + + (if (= n 0) + + #;(= n 1) + + 1 ; identity of * + + (* n (fact (- n 1)))))) diff --git a/tests/examplefiles/resourcebundle_demo b/tests/examplefiles/resourcebundle_demo new file mode 100644 index 00000000..e1daa56a --- /dev/null +++ b/tests/examplefiles/resourcebundle_demo @@ -0,0 +1,9 @@ +root:table { + usage:string { "Usage: genrb [Options] files" } + version:int { 122 } + errorcodes:array { + :string { "Invalid argument" } + :string { "File not found" } + :string { "\x00 \r \t \n \u1234" } + } +} diff --git a/tests/examplefiles/robotframework.txt b/tests/examplefiles/robotframework_test.txt index 63ba63e6..0d8179c0 100644 --- a/tests/examplefiles/robotframework.txt +++ b/tests/examplefiles/robotframework_test.txt @@ -6,6 +6,7 @@ Test Setup Keyword argument argument with ${VARIABLE} *** Variables *** ${VARIABLE} Variable value @{LIST} List variable here +&{DICT} Key1=Value1 Key2=Value2 *** Test Cases *** Keyword-driven example diff --git a/tests/examplefiles/rql-queries.rql b/tests/examplefiles/rql-queries.rql new file mode 100644 index 00000000..1d86df3c --- /dev/null +++ b/tests/examplefiles/rql-queries.rql @@ -0,0 +1,34 @@ +Any N, N2 where N is Note, N2 is Note, N a_faire_par P1, P1 nom 'john', N2 a_faire_par P2, P2 nom 'jane' ; +DISTINCT Any N, D, C, T, A ORDERBY D DESC LIMIT 40 where N is Note, N diem D, W is Workcase, W concerned_by N, N cost C, N text T, N author A, N diem <= today +Bookmark B WHERE B owned_by G, G eid 5; +Any X WHERE E eid 22762, NOT E is_in X, X modification_date D ORDERBY D DESC LIMIT 41; +Any A, R, SUB ORDERBY R WHERE A is "Workcase", S is Division, S concerned_by A, A subject SUB, S eid 85, A ref R; +Any D, T, L WHERE D is Document, A concerned_by D,A eid 14533, D title T, D location L; +Any N,A,B,C,D ORDERBY A DESC WHERE N is Note, W concerned_by N, W eid 14533, N diem A,N author B,N text C,N cost D; +Any X ORDERBY D DESC LIMIT 41 WHERE E eid 18134, NOT E concerned_by X, X modification_date D +DISTINCT Any N, D, C, T, A ORDERBY D ASC LIMIT 40 WHERE N is Note, N diem D, P is Person, N to_be_contacted_by G, N cost C, N text T, N author A, G login "john"; +INSERT Person X: X surname "Doe", X firstname "John"; +Workcase W where W ref "ABCD12"; +Workcase W where W ref LIKE "AB%"; +Any X WHERE X X eid 53 +Any X WHERE X Document X occurence_of F, F class C, C name 'Comics' X owned_by U, U login 'syt' X available true +Person P WHERE P work_for P, S name 'Acme', P interested_by T, T name 'training' +Note N WHERE N written_on D, D day> (today -10), N written_by P, P name 'joe' or P name 'jack' +Person P WHERE (P interested_by T, T name 'training') or (P city 'Paris') +Any N, P WHERE X is Person, X name N, X first_name P +String N, P WHERE X is Person, X name N, X first_name P +INSERT Person X: X name 'widget' +INSERT Person X, Person Y: X name 'foo', Y name 'nice', X friend Y +INSERT Person X: X name 'foo', X friend Y WHERE name 'nice' +SET X name 'bar', X first_name 'original' where X is Person X name 'foo' +SET X know Y WHERE X friend Y +DELETE Person X WHERE X name 'foo' +DELETE X friend Y WHERE X is Person, X name 'foo' +Any X WHERE X name LIKE '%lt' +Any X WHERE X name IN ( 'joe', 'jack', 'william', 'averell') +Any X, V WHERE X concerns P, P eid 42, X corrected_in V? +Any C, P WHERE C is Card, P? documented_by C +Point P where P abs X, P ord Y, P value X+Y +Document X where X class C, C name 'Cartoon', X owned_by U, U login 'joe', X available true +(Any X WHERE X is Document) UNION (Any X WHERE X is File) +Any A,B WHERE A creation_date B WITH A BEING (Any X WHERE X is Document) UNION (Any X WHERE X is File) diff --git a/tests/examplefiles/rust_example.rs b/tests/examplefiles/rust_example.rs deleted file mode 100644 index 1c0a70c3..00000000 --- a/tests/examplefiles/rust_example.rs +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// based on: -// http://shootout.alioth.debian.org/u32/benchmark.php?test=nbody&lang=java - -extern mod std; - -use core::os; - -// Using sqrt from the standard library is way slower than using libc -// directly even though std just calls libc, I guess it must be -// because the the indirection through another dynamic linker -// stub. Kind of shocking. Might be able to make it faster still with -// an llvm intrinsic. -#[nolink] -extern mod libc { - #[legacy_exports]; - fn sqrt(n: float) -> float; -} - -fn main() { - let args = os::args(); - let args = if os::getenv(~"RUST_BENCH").is_some() { - ~[~"", ~"4000000"] - } else if args.len() <= 1u { - ~[~"", ~"100000"] - } else { - args - }; - let n = int::from_str(args[1]).get(); - let mut bodies: ~[Body::props] = NBodySystem::make(); - io::println(fmt!("%f", NBodySystem::energy(bodies))); - let mut i = 0; - while i < n { - NBodySystem::advance(bodies, 0.01); - i += 1; - } - io::println(fmt!("%f", NBodySystem::energy(bodies))); -} - -mod NBodySystem { - use Body; - - pub fn make() -> ~[Body::props] { - let mut bodies: ~[Body::props] = - ~[Body::sun(), - Body::jupiter(), - Body::saturn(), - Body::uranus(), - Body::neptune()]; - - let mut px = 0.0; - let mut py = 0.0; - let mut pz = 0.0; - - let mut i = 0; - while i < 5 { - px += bodies[i].vx * bodies[i].mass; - py += bodies[i].vy * bodies[i].mass; - pz += bodies[i].vz * bodies[i].mass; - - i += 1; - } - - // side-effecting - Body::offset_momentum(&mut bodies[0], px, py, pz); - - return bodies; - } - - pub fn advance(bodies: &mut [Body::props], dt: float) { - let mut i = 0; - while i < 5 { - let mut j = i + 1; - while j < 5 { - advance_one(&mut bodies[i], - &mut bodies[j], dt); - j += 1; - } - - i += 1; - } - - i = 0; - while i < 5 { - move_(&mut bodies[i], dt); - i += 1; - } - } - - pub fn advance_one(bi: &mut Body::props, - bj: &mut Body::props, - dt: float) unsafe { - let dx = bi.x - bj.x; - let dy = bi.y - bj.y; - let dz = bi.z - bj.z; - - let dSquared = dx * dx + dy * dy + dz * dz; - - let distance = ::libc::sqrt(dSquared); - let mag = dt / (dSquared * distance); - - bi.vx -= dx * bj.mass * mag; - bi.vy -= dy * bj.mass * mag; - bi.vz -= dz * bj.mass * mag; - - bj.vx += dx * bi.mass * mag; - bj.vy += dy * bi.mass * mag; - bj.vz += dz * bi.mass * mag; - } - - pub fn move_(b: &mut Body::props, dt: float) { - b.x += dt * b.vx; - b.y += dt * b.vy; - b.z += dt * b.vz; - } - - pub fn energy(bodies: &[Body::props]) -> float unsafe { - let mut dx; - let mut dy; - let mut dz; - let mut distance; - let mut e = 0.0; - - let mut i = 0; - while i < 5 { - e += - 0.5 * bodies[i].mass * - (bodies[i].vx * bodies[i].vx + bodies[i].vy * bodies[i].vy - + bodies[i].vz * bodies[i].vz); - - let mut j = i + 1; - while j < 5 { - dx = bodies[i].x - bodies[j].x; - dy = bodies[i].y - bodies[j].y; - dz = bodies[i].z - bodies[j].z; - - distance = ::libc::sqrt(dx * dx + dy * dy + dz * dz); - e -= bodies[i].mass * bodies[j].mass / distance; - - j += 1; - } - - i += 1; - } - return e; - - } -} - -mod Body { - use Body; - - pub const PI: float = 3.141592653589793; - pub const SOLAR_MASS: float = 39.478417604357432; - // was 4 * PI * PI originally - pub const DAYS_PER_YEAR: float = 365.24; - - pub type props = - {mut x: float, - mut y: float, - mut z: float, - mut vx: float, - mut vy: float, - mut vz: float, - mass: float}; - - pub fn jupiter() -> Body::props { - return {mut x: 4.84143144246472090e+00, - mut y: -1.16032004402742839e+00, - mut z: -1.03622044471123109e-01, - mut vx: 1.66007664274403694e-03 * DAYS_PER_YEAR, - mut vy: 7.69901118419740425e-03 * DAYS_PER_YEAR, - mut vz: -6.90460016972063023e-05 * DAYS_PER_YEAR, - mass: 9.54791938424326609e-04 * SOLAR_MASS}; - } - - pub fn saturn() -> Body::props { - return {mut x: 8.34336671824457987e+00, - mut y: 4.12479856412430479e+00, - mut z: -4.03523417114321381e-01, - mut vx: -2.76742510726862411e-03 * DAYS_PER_YEAR, - mut vy: 4.99852801234917238e-03 * DAYS_PER_YEAR, - mut vz: 2.30417297573763929e-05 * DAYS_PER_YEAR, - mass: 2.85885980666130812e-04 * SOLAR_MASS}; - } - - pub fn uranus() -> Body::props { - return {mut x: 1.28943695621391310e+01, - mut y: -1.51111514016986312e+01, - mut z: -2.23307578892655734e-01, - mut vx: 2.96460137564761618e-03 * DAYS_PER_YEAR, - mut vy: 2.37847173959480950e-03 * DAYS_PER_YEAR, - mut vz: -2.96589568540237556e-05 * DAYS_PER_YEAR, - mass: 4.36624404335156298e-05 * SOLAR_MASS}; - } - - pub fn neptune() -> Body::props { - return {mut x: 1.53796971148509165e+01, - mut y: -2.59193146099879641e+01, - mut z: 1.79258772950371181e-01, - mut vx: 2.68067772490389322e-03 * DAYS_PER_YEAR, - mut vy: 1.62824170038242295e-03 * DAYS_PER_YEAR, - mut vz: -9.51592254519715870e-05 * DAYS_PER_YEAR, - mass: 5.15138902046611451e-05 * SOLAR_MASS}; - } - - pub fn sun() -> Body::props { - return {mut x: 0.0, - mut y: 0.0, - mut z: 0.0, - mut vx: 0.0, - mut vy: 0.0, - mut vz: 0.0, - mass: SOLAR_MASS}; - } - - pub fn offset_momentum(props: &mut Body::props, - px: float, py: float, pz: float) { - props.vx = -px / SOLAR_MASS; - props.vy = -py / SOLAR_MASS; - props.vz = -pz / SOLAR_MASS; - } - -} diff --git a/tests/examplefiles/scope.cirru b/tests/examplefiles/scope.cirru new file mode 100644 index 00000000..d3bd8f16 --- /dev/null +++ b/tests/examplefiles/scope.cirru @@ -0,0 +1,211 @@ + +-- demo + +define a (read cd) $ if (> a cd) + print demo + print "not demo" + +say $ print a $ save $ b $ x $ c 8 + +print fun + +-- test on folding + +a $ + +b $ c + +d $ e $ f + +g $ h $ i j $ k $ + +-- test on comma + +print (, a) + a + , b + , c (, d) + +-- test on HTML + +doctype + +html + head + title $ = Cirru + script (:defer) $ :src build/build.js + link (:rel stylesheet) $ :href css/page.css + link (:rel icon) + :href http://logo.cirru.org/cirru-32x32.png?v=3 + body + textarea.demo.source $ :placeholder "Source Code" + textarea.demo.target $ :placeholder "Compiled Data" + @insert ../html/ga.html + +-- test on indentation + +a $ b $ c + +e f + (g) + h + +-- test on parentheses + +3 4 (1) 4 + +((((1)))) + +x + +-- test on quotes + +a b c d + +"a b c d" + +"a b \" c d" + +"a b" "c d" + +-- test on unfolding + +set + add 1 $ + , x y + add 5 $ + add 2 + +-- test on HTML attributes + +div + div + :class a + div + :class a b c d + + div + :class a (@ b) (@ c) d + + div + :class a + @if (@ b) + div b + div c + div + :class a + @if (@ b) b c + +-- test on helpers + +@if (@call a b) (div) (span) + +@each members + div (@ name) + +@each a + div (@ b) + @each c + div (@ d) + +-- test on HTML structure + +@rich more + #demo-more-box + #demo-more + :data-lang-text demo-more + #demo-more-list + @each room + .demo-more-room + span.demo-name + @ topic + span.demo-join + :data-lang-text demo-join + :data-id (@ id) + +-- text on bool + +print #true +print #false +print #yes +print #no +print #t +print #f + +-- test on Cirru js + +set a 1 +set a (= "This is a string") +set b #t + +-- this is comment + +number 1.4 +string x +regex ^\s$ +regex "^\\s-\"$" +sentence this is a string + +array 1 2 3 (= nothing) #t (= #t) + +set c (array 1 (= nothing)) + +set d $ object (a (= google)) + b (= reader) + c 1 + d $ array 1 2 (= string) + +1 c +-1 c + +:b d +.log console a 2 +.log console + +set demo $ object + call $ \ x (.log console x) (. this call) +. demo (.call 1) (.call 4) + +=.x d 3 + +set d null + +new Array 1 2 3 + +set x (:length c) +set str (= str) +set c (.toUpperCase str) + +\ x (+ x 1) +\ (x y) (+ x y) +\ x (set aa 1) (+ aa x) + +set f (\ x (+ x 1)) + ++ a 1 2 ++= a 1 + +> 1 2 3 + +if (> 2 1) (+ a 1) +else 2 + +if (> a 2) + .log console (= "large") +elseif (> a 1) + .log console (= "still good") +else + .log console (= "so so") + +set a $ if (> 2 1) #t #f + +switch a + 1 (.log console 1) + 2 (.log console 2) + else (.log console (= "something else")) + +set a $ array 2 +3 -4 +for (a x i) (.log console x i) + +set a 0 +while (< a 10) (+= a 1) (.log console a) diff --git a/tests/examplefiles/simple.md b/tests/examplefiles/simple.croc index 8f12771a..8f12771a 100644 --- a/tests/examplefiles/simple.md +++ b/tests/examplefiles/simple.croc diff --git a/tests/examplefiles/sparql.rq b/tests/examplefiles/sparql.rq new file mode 100644 index 00000000..caedfd14 --- /dev/null +++ b/tests/examplefiles/sparql.rq @@ -0,0 +1,23 @@ +# This is a test SPARQL query + +PREFIX foaf: <http://xmlns.com/foaf/0.1/> +PREFIX ex: <http://example.org/> +PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> +PREFIX dcterms: <http://purl.org/dc/terms/> + +SELECT ?person (COUNT(?nick) AS ?nickCount) { + ?person foaf:nick ?nick ; + foaf:lastName "Smith" ; + foaf:age "21"^^xsd:int ; + ex:title 'Mr' ; # single-quoted string + ex:height 1.80 ; # float + ex:distanceToSun +1.4e8 ; # float with exponent + ex:ownsACat true ; + dcterms:description "Someone with a cat called \"cat\"."@en . + OPTIONAL { ?person foaf:isPrimaryTopicOf ?page } + OPTIONAL { ?person foaf:name ?name + { ?person foaf:depiction ?img } + UNION + { ?person foaf:firstName ?firstN } } + FILTER ( bound(?page) || bound(?img) || bound(?firstN) ) +} GROUP BY ?person ORDER BY ?img diff --git a/tests/examplefiles/subr.el b/tests/examplefiles/subr.el new file mode 100644 index 00000000..deadca6e --- /dev/null +++ b/tests/examplefiles/subr.el @@ -0,0 +1,4868 @@ +;;; subr.el --- basic lisp subroutines for Emacs -*- coding: utf-8; lexical-binding:t -*- + +;; Copyright (C) 1985-1986, 1992, 1994-1995, 1999-2015 Free Software +;; Foundation, Inc. + +;; Maintainer: emacs-devel@gnu.org +;; Keywords: internal +;; Package: emacs + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;;; Code: + +;; Beware: while this file has tag `utf-8', before it's compiled, it gets +;; loaded as "raw-text", so non-ASCII chars won't work right during bootstrap. + +(defmacro declare-function (_fn _file &optional _arglist _fileonly) + "Tell the byte-compiler that function FN is defined, in FILE. +Optional ARGLIST is the argument list used by the function. +The FILE argument is not used by the byte-compiler, but by the +`check-declare' package, which checks that FILE contains a +definition for FN. ARGLIST is used by both the byte-compiler +and `check-declare' to check for consistency. + +FILE can be either a Lisp file (in which case the \".el\" +extension is optional), or a C file. C files are expanded +relative to the Emacs \"src/\" directory. Lisp files are +searched for using `locate-library', and if that fails they are +expanded relative to the location of the file containing the +declaration. A FILE with an \"ext:\" prefix is an external file. +`check-declare' will check such files if they are found, and skip +them without error if they are not. + +FILEONLY non-nil means that `check-declare' will only check that +FILE exists, not that it defines FN. This is intended for +function-definitions that `check-declare' does not recognize, e.g. +`defstruct'. + +To specify a value for FILEONLY without passing an argument list, +set ARGLIST to t. This is necessary because nil means an +empty argument list, rather than an unspecified one. + +Note that for the purposes of `check-declare', this statement +must be the first non-whitespace on a line. + +For more information, see Info node `(elisp)Declaring Functions'." + ;; Does nothing - byte-compile-declare-function does the work. + nil) + + +;;;; Basic Lisp macros. + +(defalias 'not 'null) + +(defmacro noreturn (form) + "Evaluate FORM, expecting it not to return. +If FORM does return, signal an error." + (declare (debug t)) + `(prog1 ,form + (error "Form marked with `noreturn' did return"))) + +(defmacro 1value (form) + "Evaluate FORM, expecting a constant return value. +This is the global do-nothing version. There is also `testcover-1value' +that complains if FORM ever does return differing values." + (declare (debug t)) + form) + +(defmacro def-edebug-spec (symbol spec) + "Set the `edebug-form-spec' property of SYMBOL according to SPEC. +Both SYMBOL and SPEC are unevaluated. The SPEC can be: +0 (instrument no arguments); t (instrument all arguments); +a symbol (naming a function with an Edebug specification); or a list. +The elements of the list describe the argument types; see +Info node `(elisp)Specification List' for details." + `(put (quote ,symbol) 'edebug-form-spec (quote ,spec))) + +(defmacro lambda (&rest cdr) + "Return a lambda expression. +A call of the form (lambda ARGS DOCSTRING INTERACTIVE BODY) is +self-quoting; the result of evaluating the lambda expression is the +expression itself. The lambda expression may then be treated as a +function, i.e., stored as the function value of a symbol, passed to +`funcall' or `mapcar', etc. + +ARGS should take the same form as an argument list for a `defun'. +DOCSTRING is an optional documentation string. + If present, it should describe how to call the function. + But documentation strings are usually not useful in nameless functions. +INTERACTIVE should be a call to the function `interactive', which see. +It may also be omitted. +BODY should be a list of Lisp expressions. + +\(fn ARGS [DOCSTRING] [INTERACTIVE] BODY)" + (declare (doc-string 2) (indent defun) + (debug (&define lambda-list + [&optional stringp] + [&optional ("interactive" interactive)] + def-body))) + ;; Note that this definition should not use backquotes; subr.el should not + ;; depend on backquote.el. + (list 'function (cons 'lambda cdr))) + +(defmacro setq-local (var val) + "Set variable VAR to value VAL in current buffer." + ;; Can't use backquote here, it's too early in the bootstrap. + (list 'set (list 'make-local-variable (list 'quote var)) val)) + +(defmacro defvar-local (var val &optional docstring) + "Define VAR as a buffer-local variable with default value VAL. +Like `defvar' but additionally marks the variable as being automatically +buffer-local wherever it is set." + (declare (debug defvar) (doc-string 3)) + ;; Can't use backquote here, it's too early in the bootstrap. + (list 'progn (list 'defvar var val docstring) + (list 'make-variable-buffer-local (list 'quote var)))) + +(defun apply-partially (fun &rest args) + "Return a function that is a partial application of FUN to ARGS. +ARGS is a list of the first N arguments to pass to FUN. +The result is a new function which does the same as FUN, except that +the first N arguments are fixed at the values with which this function +was called." + (lambda (&rest args2) + (apply fun (append args args2)))) + +(defmacro push (newelt place) + "Add NEWELT to the list stored in the generalized variable PLACE. +This is morally equivalent to (setf PLACE (cons NEWELT PLACE)), +except that PLACE is only evaluated once (after NEWELT)." + (declare (debug (form gv-place))) + (if (symbolp place) + ;; Important special case, to avoid triggering GV too early in + ;; the bootstrap. + (list 'setq place + (list 'cons newelt place)) + (require 'macroexp) + (macroexp-let2 macroexp-copyable-p v newelt + (gv-letplace (getter setter) place + (funcall setter `(cons ,v ,getter)))))) + +(defmacro pop (place) + "Return the first element of PLACE's value, and remove it from the list. +PLACE must be a generalized variable whose value is a list. +If the value is nil, `pop' returns nil but does not actually +change the list." + (declare (debug (gv-place))) + ;; We use `car-safe' here instead of `car' because the behavior is the same + ;; (if it's not a cons cell, the `cdr' would have signaled an error already), + ;; but `car-safe' is total, so the byte-compiler can safely remove it if the + ;; result is not used. + `(car-safe + ,(if (symbolp place) + ;; So we can use `pop' in the bootstrap before `gv' can be used. + (list 'prog1 place (list 'setq place (list 'cdr place))) + (gv-letplace (getter setter) place + (macroexp-let2 macroexp-copyable-p x getter + `(prog1 ,x ,(funcall setter `(cdr ,x)))))))) + +(defmacro when (cond &rest body) + "If COND yields non-nil, do BODY, else return nil. +When COND yields non-nil, eval BODY forms sequentially and return +value of last one, or nil if there are none. + +\(fn COND BODY...)" + (declare (indent 1) (debug t)) + (list 'if cond (cons 'progn body))) + +(defmacro unless (cond &rest body) + "If COND yields nil, do BODY, else return nil. +When COND yields nil, eval BODY forms sequentially and return +value of last one, or nil if there are none. + +\(fn COND BODY...)" + (declare (indent 1) (debug t)) + (cons 'if (cons cond (cons nil body)))) + +(defmacro dolist (spec &rest body) + "Loop over a list. +Evaluate BODY with VAR bound to each car from LIST, in turn. +Then evaluate RESULT to get return value, default nil. + +\(fn (VAR LIST [RESULT]) BODY...)" + (declare (indent 1) (debug ((symbolp form &optional form) body))) + ;; It would be cleaner to create an uninterned symbol, + ;; but that uses a lot more space when many functions in many files + ;; use dolist. + ;; FIXME: This cost disappears in byte-compiled lexical-binding files. + (let ((temp '--dolist-tail--)) + ;; This is not a reliable test, but it does not matter because both + ;; semantics are acceptable, tho one is slightly faster with dynamic + ;; scoping and the other is slightly faster (and has cleaner semantics) + ;; with lexical scoping. + (if lexical-binding + `(let ((,temp ,(nth 1 spec))) + (while ,temp + (let ((,(car spec) (car ,temp))) + ,@body + (setq ,temp (cdr ,temp)))) + ,@(cdr (cdr spec))) + `(let ((,temp ,(nth 1 spec)) + ,(car spec)) + (while ,temp + (setq ,(car spec) (car ,temp)) + ,@body + (setq ,temp (cdr ,temp))) + ,@(if (cdr (cdr spec)) + `((setq ,(car spec) nil) ,@(cdr (cdr spec)))))))) + +(defmacro dotimes (spec &rest body) + "Loop a certain number of times. +Evaluate BODY with VAR bound to successive integers running from 0, +inclusive, to COUNT, exclusive. Then evaluate RESULT to get +the return value (nil if RESULT is omitted). + +\(fn (VAR COUNT [RESULT]) BODY...)" + (declare (indent 1) (debug dolist)) + ;; It would be cleaner to create an uninterned symbol, + ;; but that uses a lot more space when many functions in many files + ;; use dotimes. + ;; FIXME: This cost disappears in byte-compiled lexical-binding files. + (let ((temp '--dotimes-limit--) + (start 0) + (end (nth 1 spec))) + ;; This is not a reliable test, but it does not matter because both + ;; semantics are acceptable, tho one is slightly faster with dynamic + ;; scoping and the other has cleaner semantics. + (if lexical-binding + (let ((counter '--dotimes-counter--)) + `(let ((,temp ,end) + (,counter ,start)) + (while (< ,counter ,temp) + (let ((,(car spec) ,counter)) + ,@body) + (setq ,counter (1+ ,counter))) + ,@(if (cddr spec) + ;; FIXME: This let often leads to "unused var" warnings. + `((let ((,(car spec) ,counter)) ,@(cddr spec)))))) + `(let ((,temp ,end) + (,(car spec) ,start)) + (while (< ,(car spec) ,temp) + ,@body + (setq ,(car spec) (1+ ,(car spec)))) + ,@(cdr (cdr spec)))))) + +(defmacro declare (&rest _specs) + "Do not evaluate any arguments, and return nil. +If a `declare' form appears as the first form in the body of a +`defun' or `defmacro' form, SPECS specifies various additional +information about the function or macro; these go into effect +during the evaluation of the `defun' or `defmacro' form. + +The possible values of SPECS are specified by +`defun-declarations-alist' and `macro-declarations-alist'. + +For more information, see info node `(elisp)Declare Form'." + ;; FIXME: edebug spec should pay attention to defun-declarations-alist. + nil) + +(defmacro ignore-errors (&rest body) + "Execute BODY; if an error occurs, return nil. +Otherwise, return result of last form in BODY. +See also `with-demoted-errors' that does something similar +without silencing all errors." + (declare (debug t) (indent 0)) + `(condition-case nil (progn ,@body) (error nil))) + +;;;; Basic Lisp functions. + +(defun ignore (&rest _ignore) + "Do nothing and return nil. +This function accepts any number of arguments, but ignores them." + (interactive) + nil) + +;; Signal a compile-error if the first arg is missing. +(defun error (&rest args) + "Signal an error, making error message by passing all args to `format'. +In Emacs, the convention is that error messages start with a capital +letter but *do not* end with a period. Please follow this convention +for the sake of consistency." + (declare (advertised-calling-convention (string &rest args) "23.1")) + (signal 'error (list (apply 'format args)))) + +(defun user-error (format &rest args) + "Signal a pilot error, making error message by passing all args to `format'. +In Emacs, the convention is that error messages start with a capital +letter but *do not* end with a period. Please follow this convention +for the sake of consistency. +This is just like `error' except that `user-error's are expected to be the +result of an incorrect manipulation on the part of the user, rather than the +result of an actual problem." + (signal 'user-error (list (apply #'format format args)))) + +(defun define-error (name message &optional parent) + "Define NAME as a new error signal. +MESSAGE is a string that will be output to the echo area if such an error +is signaled without being caught by a `condition-case'. +PARENT is either a signal or a list of signals from which it inherits. +Defaults to `error'." + (unless parent (setq parent 'error)) + (let ((conditions + (if (consp parent) + (apply #'append + (mapcar (lambda (parent) + (cons parent + (or (get parent 'error-conditions) + (error "Unknown signal `%s'" parent)))) + parent)) + (cons parent (get parent 'error-conditions))))) + (put name 'error-conditions + (delete-dups (copy-sequence (cons name conditions)))) + (when message (put name 'error-message message)))) + +;; We put this here instead of in frame.el so that it's defined even on +;; systems where frame.el isn't loaded. +(defun frame-configuration-p (object) + "Return non-nil if OBJECT seems to be a frame configuration. +Any list whose car is `frame-configuration' is assumed to be a frame +configuration." + (and (consp object) + (eq (car object) 'frame-configuration))) + + +;;;; List functions. + +(defsubst caar (x) + "Return the car of the car of X." + (car (car x))) + +(defsubst cadr (x) + "Return the car of the cdr of X." + (car (cdr x))) + +(defsubst cdar (x) + "Return the cdr of the car of X." + (cdr (car x))) + +(defsubst cddr (x) + "Return the cdr of the cdr of X." + (cdr (cdr x))) + +(defun last (list &optional n) + "Return the last link of LIST. Its car is the last element. +If LIST is nil, return nil. +If N is non-nil, return the Nth-to-last link of LIST. +If N is bigger than the length of LIST, return LIST." + (if n + (and (>= n 0) + (let ((m (safe-length list))) + (if (< n m) (nthcdr (- m n) list) list))) + (and list + (nthcdr (1- (safe-length list)) list)))) + +(defun butlast (list &optional n) + "Return a copy of LIST with the last N elements removed. +If N is omitted or nil, the last element is removed from the +copy." + (if (and n (<= n 0)) list + (nbutlast (copy-sequence list) n))) + +(defun nbutlast (list &optional n) + "Modifies LIST to remove the last N elements. +If N is omitted or nil, remove the last element." + (let ((m (length list))) + (or n (setq n 1)) + (and (< n m) + (progn + (if (> n 0) (setcdr (nthcdr (- (1- m) n) list) nil)) + list)))) + +(defun zerop (number) + "Return t if NUMBER is zero." + ;; Used to be in C, but it's pointless since (= 0 n) is faster anyway because + ;; = has a byte-code. + (declare (compiler-macro (lambda (_) `(= 0 ,number)))) + (= 0 number)) + +(defun delete-dups (list) + "Destructively remove `equal' duplicates from LIST. +Store the result in LIST and return it. LIST must be a proper list. +Of several `equal' occurrences of an element in LIST, the first +one is kept." + (let ((tail list)) + (while tail + (setcdr tail (delete (car tail) (cdr tail))) + (setq tail (cdr tail)))) + list) + +;; See http://lists.gnu.org/archive/html/emacs-devel/2013-05/msg00204.html +(defun delete-consecutive-dups (list &optional circular) + "Destructively remove `equal' consecutive duplicates from LIST. +First and last elements are considered consecutive if CIRCULAR is +non-nil." + (let ((tail list) last) + (while (consp tail) + (if (equal (car tail) (cadr tail)) + (setcdr tail (cddr tail)) + (setq last (car tail) + tail (cdr tail)))) + (if (and circular + (cdr list) + (equal last (car list))) + (nbutlast list) + list))) + +(defun number-sequence (from &optional to inc) + "Return a sequence of numbers from FROM to TO (both inclusive) as a list. +INC is the increment used between numbers in the sequence and defaults to 1. +So, the Nth element of the list is (+ FROM (* N INC)) where N counts from +zero. TO is only included if there is an N for which TO = FROM + N * INC. +If TO is nil or numerically equal to FROM, return (FROM). +If INC is positive and TO is less than FROM, or INC is negative +and TO is larger than FROM, return nil. +If INC is zero and TO is neither nil nor numerically equal to +FROM, signal an error. + +This function is primarily designed for integer arguments. +Nevertheless, FROM, TO and INC can be integer or float. However, +floating point arithmetic is inexact. For instance, depending on +the machine, it may quite well happen that +\(number-sequence 0.4 0.6 0.2) returns the one element list (0.4), +whereas (number-sequence 0.4 0.8 0.2) returns a list with three +elements. Thus, if some of the arguments are floats and one wants +to make sure that TO is included, one may have to explicitly write +TO as (+ FROM (* N INC)) or use a variable whose value was +computed with this exact expression. Alternatively, you can, +of course, also replace TO with a slightly larger value +\(or a slightly more negative value if INC is negative)." + (if (or (not to) (= from to)) + (list from) + (or inc (setq inc 1)) + (when (zerop inc) (error "The increment can not be zero")) + (let (seq (n 0) (next from)) + (if (> inc 0) + (while (<= next to) + (setq seq (cons next seq) + n (1+ n) + next (+ from (* n inc)))) + (while (>= next to) + (setq seq (cons next seq) + n (1+ n) + next (+ from (* n inc))))) + (nreverse seq)))) + +(defun copy-tree (tree &optional vecp) + "Make a copy of TREE. +If TREE is a cons cell, this recursively copies both its car and its cdr. +Contrast to `copy-sequence', which copies only along the cdrs. With second +argument VECP, this copies vectors as well as conses." + (if (consp tree) + (let (result) + (while (consp tree) + (let ((newcar (car tree))) + (if (or (consp (car tree)) (and vecp (vectorp (car tree)))) + (setq newcar (copy-tree (car tree) vecp))) + (push newcar result)) + (setq tree (cdr tree))) + (nconc (nreverse result) tree)) + (if (and vecp (vectorp tree)) + (let ((i (length (setq tree (copy-sequence tree))))) + (while (>= (setq i (1- i)) 0) + (aset tree i (copy-tree (aref tree i) vecp))) + tree) + tree))) + +;;;; Various list-search functions. + +(defun assoc-default (key alist &optional test default) + "Find object KEY in a pseudo-alist ALIST. +ALIST is a list of conses or objects. Each element + (or the element's car, if it is a cons) is compared with KEY by + calling TEST, with two arguments: (i) the element or its car, + and (ii) KEY. +If that is non-nil, the element matches; then `assoc-default' + returns the element's cdr, if it is a cons, or DEFAULT if the + element is not a cons. + +If no element matches, the value is nil. +If TEST is omitted or nil, `equal' is used." + (let (found (tail alist) value) + (while (and tail (not found)) + (let ((elt (car tail))) + (when (funcall (or test 'equal) (if (consp elt) (car elt) elt) key) + (setq found t value (if (consp elt) (cdr elt) default)))) + (setq tail (cdr tail))) + value)) + +(defun assoc-ignore-case (key alist) + "Like `assoc', but ignores differences in case and text representation. +KEY must be a string. Upper-case and lower-case letters are treated as equal. +Unibyte strings are converted to multibyte for comparison." + (declare (obsolete assoc-string "22.1")) + (assoc-string key alist t)) + +(defun assoc-ignore-representation (key alist) + "Like `assoc', but ignores differences in text representation. +KEY must be a string. +Unibyte strings are converted to multibyte for comparison." + (declare (obsolete assoc-string "22.1")) + (assoc-string key alist nil)) + +(defun member-ignore-case (elt list) + "Like `member', but ignore differences in case and text representation. +ELT must be a string. Upper-case and lower-case letters are treated as equal. +Unibyte strings are converted to multibyte for comparison. +Non-strings in LIST are ignored." + (while (and list + (not (and (stringp (car list)) + (eq t (compare-strings elt 0 nil (car list) 0 nil t))))) + (setq list (cdr list))) + list) + +(defun assq-delete-all (key alist) + "Delete from ALIST all elements whose car is `eq' to KEY. +Return the modified alist. +Elements of ALIST that are not conses are ignored." + (while (and (consp (car alist)) + (eq (car (car alist)) key)) + (setq alist (cdr alist))) + (let ((tail alist) tail-cdr) + (while (setq tail-cdr (cdr tail)) + (if (and (consp (car tail-cdr)) + (eq (car (car tail-cdr)) key)) + (setcdr tail (cdr tail-cdr)) + (setq tail tail-cdr)))) + alist) + +(defun rassq-delete-all (value alist) + "Delete from ALIST all elements whose cdr is `eq' to VALUE. +Return the modified alist. +Elements of ALIST that are not conses are ignored." + (while (and (consp (car alist)) + (eq (cdr (car alist)) value)) + (setq alist (cdr alist))) + (let ((tail alist) tail-cdr) + (while (setq tail-cdr (cdr tail)) + (if (and (consp (car tail-cdr)) + (eq (cdr (car tail-cdr)) value)) + (setcdr tail (cdr tail-cdr)) + (setq tail tail-cdr)))) + alist) + +(defun alist-get (key alist &optional default remove) + "Get the value associated to KEY in ALIST. +DEFAULT is the value to return if KEY is not found in ALIST. +REMOVE, if non-nil, means that when setting this element, we should +remove the entry if the new value is `eql' to DEFAULT." + (ignore remove) ;;Silence byte-compiler. + (let ((x (assq key alist))) + (if x (cdr x) default))) + +(defun remove (elt seq) + "Return a copy of SEQ with all occurrences of ELT removed. +SEQ must be a list, vector, or string. The comparison is done with `equal'." + (if (nlistp seq) + ;; If SEQ isn't a list, there's no need to copy SEQ because + ;; `delete' will return a new object. + (delete elt seq) + (delete elt (copy-sequence seq)))) + +(defun remq (elt list) + "Return LIST with all occurrences of ELT removed. +The comparison is done with `eq'. Contrary to `delq', this does not use +side-effects, and the argument LIST is not modified." + (while (and (eq elt (car list)) (setq list (cdr list)))) + (if (memq elt list) + (delq elt (copy-sequence list)) + list)) + +;;;; Keymap support. + +(defun kbd (keys) + "Convert KEYS to the internal Emacs key representation. +KEYS should be a string constant in the format used for +saving keyboard macros (see `edmacro-mode')." + ;; Don't use a defalias, since the `pure' property is only true for + ;; the calling convention of `kbd'. + (read-kbd-macro keys)) +(put 'kbd 'pure t) + +(defun undefined () + "Beep to tell the user this binding is undefined." + (interactive) + (ding) + (message "%s is undefined" (key-description (this-single-command-keys))) + (setq defining-kbd-macro nil) + (force-mode-line-update) + ;; If this is a down-mouse event, don't reset prefix-arg; + ;; pass it to the command run by the up event. + (setq prefix-arg + (when (memq 'down (event-modifiers last-command-event)) + current-prefix-arg))) + +;; Prevent the \{...} documentation construct +;; from mentioning keys that run this command. +(put 'undefined 'suppress-keymap t) + +(defun suppress-keymap (map &optional nodigits) + "Make MAP override all normally self-inserting keys to be undefined. +Normally, as an exception, digits and minus-sign are set to make prefix args, +but optional second arg NODIGITS non-nil treats them like other chars." + (define-key map [remap self-insert-command] 'undefined) + (or nodigits + (let (loop) + (define-key map "-" 'negative-argument) + ;; Make plain numbers do numeric args. + (setq loop ?0) + (while (<= loop ?9) + (define-key map (char-to-string loop) 'digit-argument) + (setq loop (1+ loop)))))) + +(defun make-composed-keymap (maps &optional parent) + "Construct a new keymap composed of MAPS and inheriting from PARENT. +When looking up a key in the returned map, the key is looked in each +keymap of MAPS in turn until a binding is found. +If no binding is found in MAPS, the lookup continues in PARENT, if non-nil. +As always with keymap inheritance, a nil binding in MAPS overrides +any corresponding binding in PARENT, but it does not override corresponding +bindings in other keymaps of MAPS. +MAPS can be a list of keymaps or a single keymap. +PARENT if non-nil should be a keymap." + `(keymap + ,@(if (keymapp maps) (list maps) maps) + ,@parent)) + +(defun define-key-after (keymap key definition &optional after) + "Add binding in KEYMAP for KEY => DEFINITION, right after AFTER's binding. +This is like `define-key' except that the binding for KEY is placed +just after the binding for the event AFTER, instead of at the beginning +of the map. Note that AFTER must be an event type (like KEY), NOT a command +\(like DEFINITION). + +If AFTER is t or omitted, the new binding goes at the end of the keymap. +AFTER should be a single event type--a symbol or a character, not a sequence. + +Bindings are always added before any inherited map. + +The order of bindings in a keymap only matters when it is used as +a menu, so this function is not useful for non-menu keymaps." + (unless after (setq after t)) + (or (keymapp keymap) + (signal 'wrong-type-argument (list 'keymapp keymap))) + (setq key + (if (<= (length key) 1) (aref key 0) + (setq keymap (lookup-key keymap + (apply 'vector + (butlast (mapcar 'identity key))))) + (aref key (1- (length key))))) + (let ((tail keymap) done inserted) + (while (and (not done) tail) + ;; Delete any earlier bindings for the same key. + (if (eq (car-safe (car (cdr tail))) key) + (setcdr tail (cdr (cdr tail)))) + ;; If we hit an included map, go down that one. + (if (keymapp (car tail)) (setq tail (car tail))) + ;; When we reach AFTER's binding, insert the new binding after. + ;; If we reach an inherited keymap, insert just before that. + ;; If we reach the end of this keymap, insert at the end. + (if (or (and (eq (car-safe (car tail)) after) + (not (eq after t))) + (eq (car (cdr tail)) 'keymap) + (null (cdr tail))) + (progn + ;; Stop the scan only if we find a parent keymap. + ;; Keep going past the inserted element + ;; so we can delete any duplications that come later. + (if (eq (car (cdr tail)) 'keymap) + (setq done t)) + ;; Don't insert more than once. + (or inserted + (setcdr tail (cons (cons key definition) (cdr tail)))) + (setq inserted t))) + (setq tail (cdr tail))))) + +(defun map-keymap-sorted (function keymap) + "Implement `map-keymap' with sorting. +Don't call this function; it is for internal use only." + (let (list) + (map-keymap (lambda (a b) (push (cons a b) list)) + keymap) + (setq list (sort list + (lambda (a b) + (setq a (car a) b (car b)) + (if (integerp a) + (if (integerp b) (< a b) + t) + (if (integerp b) t + ;; string< also accepts symbols. + (string< a b)))))) + (dolist (p list) + (funcall function (car p) (cdr p))))) + +(defun keymap--menu-item-binding (val) + "Return the binding part of a menu-item." + (cond + ((not (consp val)) val) ;Not a menu-item. + ((eq 'menu-item (car val)) + (let* ((binding (nth 2 val)) + (plist (nthcdr 3 val)) + (filter (plist-get plist :filter))) + (if filter (funcall filter binding) + binding))) + ((and (consp (cdr val)) (stringp (cadr val))) + (cddr val)) + ((stringp (car val)) + (cdr val)) + (t val))) ;Not a menu-item either. + +(defun keymap--menu-item-with-binding (item binding) + "Build a menu-item like ITEM but with its binding changed to BINDING." + (cond + ((not (consp item)) binding) ;Not a menu-item. + ((eq 'menu-item (car item)) + (setq item (copy-sequence item)) + (let ((tail (nthcdr 2 item))) + (setcar tail binding) + ;; Remove any potential filter. + (if (plist-get (cdr tail) :filter) + (setcdr tail (plist-put (cdr tail) :filter nil)))) + item) + ((and (consp (cdr item)) (stringp (cadr item))) + (cons (car item) (cons (cadr item) binding))) + (t (cons (car item) binding)))) + +(defun keymap--merge-bindings (val1 val2) + "Merge bindings VAL1 and VAL2." + (let ((map1 (keymap--menu-item-binding val1)) + (map2 (keymap--menu-item-binding val2))) + (if (not (and (keymapp map1) (keymapp map2))) + ;; There's nothing to merge: val1 takes precedence. + val1 + (let ((map (list 'keymap map1 map2)) + (item (if (keymapp val1) (if (keymapp val2) nil val2) val1))) + (keymap--menu-item-with-binding item map))))) + +(defun keymap-canonicalize (map) + "Return a simpler equivalent keymap. +This resolves inheritance and redefinitions. The returned keymap +should behave identically to a copy of KEYMAP w.r.t `lookup-key' +and use in active keymaps and menus. +Subkeymaps may be modified but are not canonicalized." + ;; FIXME: Problem with the difference between a nil binding + ;; that hides a binding in an inherited map and a nil binding that's ignored + ;; to let some further binding visible. Currently a nil binding hides all. + ;; FIXME: we may want to carefully (re)order elements in case they're + ;; menu-entries. + (let ((bindings ()) + (ranges ()) + (prompt (keymap-prompt map))) + (while (keymapp map) + (setq map (map-keymap ;; -internal + (lambda (key item) + (if (consp key) + ;; Treat char-ranges specially. + (push (cons key item) ranges) + (push (cons key item) bindings))) + map))) + ;; Create the new map. + (setq map (funcall (if ranges 'make-keymap 'make-sparse-keymap) prompt)) + (dolist (binding ranges) + ;; Treat char-ranges specially. FIXME: need to merge as well. + (define-key map (vector (car binding)) (cdr binding))) + ;; Process the bindings starting from the end. + (dolist (binding (prog1 bindings (setq bindings ()))) + (let* ((key (car binding)) + (oldbind (assq key bindings))) + (push (if (not oldbind) + ;; The normal case: no duplicate bindings. + binding + ;; This is the second binding for this key. + (setq bindings (delq oldbind bindings)) + (cons key (keymap--merge-bindings (cdr binding) + (cdr oldbind)))) + bindings))) + (nconc map bindings))) + +(put 'keyboard-translate-table 'char-table-extra-slots 0) + +(defun keyboard-translate (from to) + "Translate character FROM to TO on the current terminal. +This function creates a `keyboard-translate-table' if necessary +and then modifies one entry in it." + (or (char-table-p keyboard-translate-table) + (setq keyboard-translate-table + (make-char-table 'keyboard-translate-table nil))) + (aset keyboard-translate-table from to)) + +;;;; Key binding commands. + +(defun global-set-key (key command) + "Give KEY a global binding as COMMAND. +COMMAND is the command definition to use; usually it is +a symbol naming an interactively-callable function. +KEY is a key sequence; noninteractively, it is a string or vector +of characters or event types, and non-ASCII characters with codes +above 127 (such as ISO Latin-1) can be included if you use a vector. + +Note that if KEY has a local binding in the current buffer, +that local binding will continue to shadow any global binding +that you make with this function." + (interactive "KSet key globally: \nCSet key %s to command: ") + (or (vectorp key) (stringp key) + (signal 'wrong-type-argument (list 'arrayp key))) + (define-key (current-global-map) key command)) + +(defun local-set-key (key command) + "Give KEY a local binding as COMMAND. +COMMAND is the command definition to use; usually it is +a symbol naming an interactively-callable function. +KEY is a key sequence; noninteractively, it is a string or vector +of characters or event types, and non-ASCII characters with codes +above 127 (such as ISO Latin-1) can be included if you use a vector. + +The binding goes in the current buffer's local map, which in most +cases is shared with all other buffers in the same major mode." + (interactive "KSet key locally: \nCSet key %s locally to command: ") + (let ((map (current-local-map))) + (or map + (use-local-map (setq map (make-sparse-keymap)))) + (or (vectorp key) (stringp key) + (signal 'wrong-type-argument (list 'arrayp key))) + (define-key map key command))) + +(defun global-unset-key (key) + "Remove global binding of KEY. +KEY is a string or vector representing a sequence of keystrokes." + (interactive "kUnset key globally: ") + (global-set-key key nil)) + +(defun local-unset-key (key) + "Remove local binding of KEY. +KEY is a string or vector representing a sequence of keystrokes." + (interactive "kUnset key locally: ") + (if (current-local-map) + (local-set-key key nil)) + nil) + +;;;; substitute-key-definition and its subroutines. + +(defvar key-substitution-in-progress nil + "Used internally by `substitute-key-definition'.") + +(defun substitute-key-definition (olddef newdef keymap &optional oldmap prefix) + "Replace OLDDEF with NEWDEF for any keys in KEYMAP now defined as OLDDEF. +In other words, OLDDEF is replaced with NEWDEF where ever it appears. +Alternatively, if optional fourth argument OLDMAP is specified, we redefine +in KEYMAP as NEWDEF those keys which are defined as OLDDEF in OLDMAP. + +If you don't specify OLDMAP, you can usually get the same results +in a cleaner way with command remapping, like this: + (define-key KEYMAP [remap OLDDEF] NEWDEF) +\n(fn OLDDEF NEWDEF KEYMAP &optional OLDMAP)" + ;; Don't document PREFIX in the doc string because we don't want to + ;; advertise it. It's meant for recursive calls only. Here's its + ;; meaning + + ;; If optional argument PREFIX is specified, it should be a key + ;; prefix, a string. Redefined bindings will then be bound to the + ;; original key, with PREFIX added at the front. + (or prefix (setq prefix "")) + (let* ((scan (or oldmap keymap)) + (prefix1 (vconcat prefix [nil])) + (key-substitution-in-progress + (cons scan key-substitution-in-progress))) + ;; Scan OLDMAP, finding each char or event-symbol that + ;; has any definition, and act on it with hack-key. + (map-keymap + (lambda (char defn) + (aset prefix1 (length prefix) char) + (substitute-key-definition-key defn olddef newdef prefix1 keymap)) + scan))) + +(defun substitute-key-definition-key (defn olddef newdef prefix keymap) + (let (inner-def skipped menu-item) + ;; Find the actual command name within the binding. + (if (eq (car-safe defn) 'menu-item) + (setq menu-item defn defn (nth 2 defn)) + ;; Skip past menu-prompt. + (while (stringp (car-safe defn)) + (push (pop defn) skipped)) + ;; Skip past cached key-equivalence data for menu items. + (if (consp (car-safe defn)) + (setq defn (cdr defn)))) + (if (or (eq defn olddef) + ;; Compare with equal if definition is a key sequence. + ;; That is useful for operating on function-key-map. + (and (or (stringp defn) (vectorp defn)) + (equal defn olddef))) + (define-key keymap prefix + (if menu-item + (let ((copy (copy-sequence menu-item))) + (setcar (nthcdr 2 copy) newdef) + copy) + (nconc (nreverse skipped) newdef))) + ;; Look past a symbol that names a keymap. + (setq inner-def + (or (indirect-function defn t) defn)) + ;; For nested keymaps, we use `inner-def' rather than `defn' so as to + ;; avoid autoloading a keymap. This is mostly done to preserve the + ;; original non-autoloading behavior of pre-map-keymap times. + (if (and (keymapp inner-def) + ;; Avoid recursively scanning + ;; where KEYMAP does not have a submap. + (let ((elt (lookup-key keymap prefix))) + (or (null elt) (natnump elt) (keymapp elt))) + ;; Avoid recursively rescanning keymap being scanned. + (not (memq inner-def key-substitution-in-progress))) + ;; If this one isn't being scanned already, scan it now. + (substitute-key-definition olddef newdef keymap inner-def prefix))))) + + +;;;; The global keymap tree. + +;; global-map, esc-map, and ctl-x-map have their values set up in +;; keymap.c; we just give them docstrings here. + +(defvar global-map nil + "Default global keymap mapping Emacs keyboard input into commands. +The value is a keymap which is usually (but not necessarily) Emacs's +global map.") + +(defvar esc-map nil + "Default keymap for ESC (meta) commands. +The normal global definition of the character ESC indirects to this keymap.") + +(defvar ctl-x-map nil + "Default keymap for C-x commands. +The normal global definition of the character C-x indirects to this keymap.") + +(defvar ctl-x-4-map (make-sparse-keymap) + "Keymap for subcommands of C-x 4.") +(defalias 'ctl-x-4-prefix ctl-x-4-map) +(define-key ctl-x-map "4" 'ctl-x-4-prefix) + +(defvar ctl-x-5-map (make-sparse-keymap) + "Keymap for frame commands.") +(defalias 'ctl-x-5-prefix ctl-x-5-map) +(define-key ctl-x-map "5" 'ctl-x-5-prefix) + + +;;;; Event manipulation functions. + +(defconst listify-key-sequence-1 (logior 128 ?\M-\C-@)) + +(defun listify-key-sequence (key) + "Convert a key sequence to a list of events." + (if (vectorp key) + (append key nil) + (mapcar (function (lambda (c) + (if (> c 127) + (logxor c listify-key-sequence-1) + c))) + key))) + +(defun eventp (obj) + "True if the argument is an event object." + (when obj + (or (integerp obj) + (and (symbolp obj) obj (not (keywordp obj))) + (and (consp obj) (symbolp (car obj)))))) + +(defun event-modifiers (event) + "Return a list of symbols representing the modifier keys in event EVENT. +The elements of the list may include `meta', `control', +`shift', `hyper', `super', `alt', `click', `double', `triple', `drag', +and `down'. +EVENT may be an event or an event type. If EVENT is a symbol +that has never been used in an event that has been read as input +in the current Emacs session, then this function may fail to include +the `click' modifier." + (let ((type event)) + (if (listp type) + (setq type (car type))) + (if (symbolp type) + ;; Don't read event-symbol-elements directly since we're not + ;; sure the symbol has already been parsed. + (cdr (internal-event-symbol-parse-modifiers type)) + (let ((list nil) + (char (logand type (lognot (logior ?\M-\^@ ?\C-\^@ ?\S-\^@ + ?\H-\^@ ?\s-\^@ ?\A-\^@))))) + (if (not (zerop (logand type ?\M-\^@))) + (push 'meta list)) + (if (or (not (zerop (logand type ?\C-\^@))) + (< char 32)) + (push 'control list)) + (if (or (not (zerop (logand type ?\S-\^@))) + (/= char (downcase char))) + (push 'shift list)) + (or (zerop (logand type ?\H-\^@)) + (push 'hyper list)) + (or (zerop (logand type ?\s-\^@)) + (push 'super list)) + (or (zerop (logand type ?\A-\^@)) + (push 'alt list)) + list)))) + +(defun event-basic-type (event) + "Return the basic type of the given event (all modifiers removed). +The value is a printing character (not upper case) or a symbol. +EVENT may be an event or an event type. If EVENT is a symbol +that has never been used in an event that has been read as input +in the current Emacs session, then this function may return nil." + (if (consp event) + (setq event (car event))) + (if (symbolp event) + (car (get event 'event-symbol-elements)) + (let* ((base (logand event (1- ?\A-\^@))) + (uncontrolled (if (< base 32) (logior base 64) base))) + ;; There are some numbers that are invalid characters and + ;; cause `downcase' to get an error. + (condition-case () + (downcase uncontrolled) + (error uncontrolled))))) + +(defsubst mouse-movement-p (object) + "Return non-nil if OBJECT is a mouse movement event." + (eq (car-safe object) 'mouse-movement)) + +(defun mouse-event-p (object) + "Return non-nil if OBJECT is a mouse click event." + ;; is this really correct? maybe remove mouse-movement? + (memq (event-basic-type object) '(mouse-1 mouse-2 mouse-3 mouse-movement))) + +(defun event-start (event) + "Return the starting position of EVENT. +EVENT should be a mouse click, drag, or key press event. If +EVENT is nil, the value of `posn-at-point' is used instead. + +The following accessor functions are used to access the elements +of the position: + +`posn-window': The window the event is in. +`posn-area': A symbol identifying the area the event occurred in, +or nil if the event occurred in the text area. +`posn-point': The buffer position of the event. +`posn-x-y': The pixel-based coordinates of the event. +`posn-col-row': The estimated column and row corresponding to the +position of the event. +`posn-actual-col-row': The actual column and row corresponding to the +position of the event. +`posn-string': The string object of the event, which is either +nil or (STRING . POSITION)'. +`posn-image': The image object of the event, if any. +`posn-object': The image or string object of the event, if any. +`posn-timestamp': The time the event occurred, in milliseconds. + +For more information, see Info node `(elisp)Click Events'." + (if (consp event) (nth 1 event) + (or (posn-at-point) + (list (selected-window) (point) '(0 . 0) 0)))) + +(defun event-end (event) + "Return the ending position of EVENT. +EVENT should be a click, drag, or key press event. + +See `event-start' for a description of the value returned." + (if (consp event) (nth (if (consp (nth 2 event)) 2 1) event) + (or (posn-at-point) + (list (selected-window) (point) '(0 . 0) 0)))) + +(defsubst event-click-count (event) + "Return the multi-click count of EVENT, a click or drag event. +The return value is a positive integer." + (if (and (consp event) (integerp (nth 2 event))) (nth 2 event) 1)) + +;;;; Extracting fields of the positions in an event. + +(defun posnp (obj) + "Return non-nil if OBJ appears to be a valid `posn' object specifying a window. +If OBJ is a valid `posn' object, but specifies a frame rather +than a window, return nil." + ;; FIXME: Correct the behavior of this function so that all valid + ;; `posn' objects are recognized, after updating other code that + ;; depends on its present behavior. + (and (windowp (car-safe obj)) + (atom (car-safe (setq obj (cdr obj)))) ;AREA-OR-POS. + (integerp (car-safe (car-safe (setq obj (cdr obj))))) ;XOFFSET. + (integerp (car-safe (cdr obj))))) ;TIMESTAMP. + +(defsubst posn-window (position) + "Return the window in POSITION. +POSITION should be a list of the form returned by the `event-start' +and `event-end' functions." + (nth 0 position)) + +(defsubst posn-area (position) + "Return the window area recorded in POSITION, or nil for the text area. +POSITION should be a list of the form returned by the `event-start' +and `event-end' functions." + (let ((area (if (consp (nth 1 position)) + (car (nth 1 position)) + (nth 1 position)))) + (and (symbolp area) area))) + +(defun posn-point (position) + "Return the buffer location in POSITION. +POSITION should be a list of the form returned by the `event-start' +and `event-end' functions. +Returns nil if POSITION does not correspond to any buffer location (e.g. +a click on a scroll bar)." + (or (nth 5 position) + (let ((pt (nth 1 position))) + (or (car-safe pt) + ;; Apparently this can also be `vertical-scroll-bar' (bug#13979). + (if (integerp pt) pt))))) + +(defun posn-set-point (position) + "Move point to POSITION. +Select the corresponding window as well." + (if (not (windowp (posn-window position))) + (error "Position not in text area of window")) + (select-window (posn-window position)) + (if (numberp (posn-point position)) + (goto-char (posn-point position)))) + +(defsubst posn-x-y (position) + "Return the x and y coordinates in POSITION. +The return value has the form (X . Y), where X and Y are given in +pixels. POSITION should be a list of the form returned by +`event-start' and `event-end'." + (nth 2 position)) + +(declare-function scroll-bar-scale "scroll-bar" (num-denom whole)) + +(defun posn-col-row (position) + "Return the nominal column and row in POSITION, measured in characters. +The column and row values are approximations calculated from the x +and y coordinates in POSITION and the frame's default character width +and default line height, including spacing. +For a scroll-bar event, the result column is 0, and the row +corresponds to the vertical position of the click in the scroll bar. +POSITION should be a list of the form returned by the `event-start' +and `event-end' functions." + (let* ((pair (posn-x-y position)) + (frame-or-window (posn-window position)) + (frame (if (framep frame-or-window) + frame-or-window + (window-frame frame-or-window))) + (window (when (windowp frame-or-window) frame-or-window)) + (area (posn-area position))) + (cond + ((null frame-or-window) + '(0 . 0)) + ((eq area 'vertical-scroll-bar) + (cons 0 (scroll-bar-scale pair (1- (window-height window))))) + ((eq area 'horizontal-scroll-bar) + (cons (scroll-bar-scale pair (window-width window)) 0)) + (t + ;; FIXME: This should take line-spacing properties on + ;; newlines into account. + (let* ((spacing (when (display-graphic-p frame) + (or (with-current-buffer + (window-buffer (frame-selected-window frame)) + line-spacing) + (frame-parameter frame 'line-spacing))))) + (cond ((floatp spacing) + (setq spacing (truncate (* spacing + (frame-char-height frame))))) + ((null spacing) + (setq spacing 0))) + (cons (/ (car pair) (frame-char-width frame)) + (/ (cdr pair) (+ (frame-char-height frame) spacing)))))))) + +(defun posn-actual-col-row (position) + "Return the window row number in POSITION and character number in that row. + +Return nil if POSITION does not contain the actual position; in that case +\`posn-col-row' can be used to get approximate values. +POSITION should be a list of the form returned by the `event-start' +and `event-end' functions. + +This function does not account for the width on display, like the +number of visual columns taken by a TAB or image. If you need +the coordinates of POSITION in character units, you should use +\`posn-col-row', not this function." + (nth 6 position)) + +(defsubst posn-timestamp (position) + "Return the timestamp of POSITION. +POSITION should be a list of the form returned by the `event-start' +and `event-end' functions." + (nth 3 position)) + +(defun posn-string (position) + "Return the string object of POSITION. +Value is a cons (STRING . STRING-POS), or nil if not a string. +POSITION should be a list of the form returned by the `event-start' +and `event-end' functions." + (let ((x (nth 4 position))) + ;; Apparently this can also be `handle' or `below-handle' (bug#13979). + (when (consp x) x))) + +(defsubst posn-image (position) + "Return the image object of POSITION. +Value is a list (image ...), or nil if not an image. +POSITION should be a list of the form returned by the `event-start' +and `event-end' functions." + (nth 7 position)) + +(defsubst posn-object (position) + "Return the object (image or string) of POSITION. +Value is a list (image ...) for an image object, a cons cell +\(STRING . STRING-POS) for a string object, and nil for a buffer position. +POSITION should be a list of the form returned by the `event-start' +and `event-end' functions." + (or (posn-image position) (posn-string position))) + +(defsubst posn-object-x-y (position) + "Return the x and y coordinates relative to the object of POSITION. +The return value has the form (DX . DY), where DX and DY are +given in pixels. POSITION should be a list of the form returned +by `event-start' and `event-end'." + (nth 8 position)) + +(defsubst posn-object-width-height (position) + "Return the pixel width and height of the object of POSITION. +The return value has the form (WIDTH . HEIGHT). POSITION should +be a list of the form returned by `event-start' and `event-end'." + (nth 9 position)) + + +;;;; Obsolescent names for functions. + +(define-obsolete-function-alias 'window-dot 'window-point "22.1") +(define-obsolete-function-alias 'set-window-dot 'set-window-point "22.1") +(define-obsolete-function-alias 'read-input 'read-string "22.1") +(define-obsolete-function-alias 'show-buffer 'set-window-buffer "22.1") +(define-obsolete-function-alias 'eval-current-buffer 'eval-buffer "22.1") +(define-obsolete-function-alias 'string-to-int 'string-to-number "22.1") + +(make-obsolete 'forward-point "use (+ (point) N) instead." "23.1") +(make-obsolete 'buffer-has-markers-at nil "24.3") + +(defun insert-string (&rest args) + "Mocklisp-compatibility insert function. +Like the function `insert' except that any argument that is a number +is converted into a string by expressing it in decimal." + (declare (obsolete insert "22.1")) + (dolist (el args) + (insert (if (integerp el) (number-to-string el) el)))) + +(defun makehash (&optional test) + (declare (obsolete make-hash-table "22.1")) + (make-hash-table :test (or test 'eql))) + +(defun log10 (x) + "Return (log X 10), the log base 10 of X." + (declare (obsolete log "24.4")) + (log x 10)) + +;; These are used by VM and some old programs +(defalias 'focus-frame 'ignore "") +(make-obsolete 'focus-frame "it does nothing." "22.1") +(defalias 'unfocus-frame 'ignore "") +(make-obsolete 'unfocus-frame "it does nothing." "22.1") +(make-obsolete 'make-variable-frame-local + "explicitly check for a frame-parameter instead." "22.2") +(set-advertised-calling-convention + 'all-completions '(string collection &optional predicate) "23.1") +(set-advertised-calling-convention 'unintern '(name obarray) "23.3") +(set-advertised-calling-convention 'indirect-function '(object) "25.1") +(set-advertised-calling-convention 'redirect-frame-focus '(frame focus-frame) "24.3") +(set-advertised-calling-convention 'decode-char '(ch charset) "21.4") +(set-advertised-calling-convention 'encode-char '(ch charset) "21.4") + +;;;; Obsolescence declarations for variables, and aliases. + +;; Special "default-FOO" variables which contain the default value of +;; the "FOO" variable are nasty. Their implementation is brittle, and +;; slows down several unrelated variable operations; furthermore, they +;; can lead to really odd behavior if you decide to make them +;; buffer-local. + +;; Not used at all in Emacs, last time I checked: +(make-obsolete-variable 'default-mode-line-format 'mode-line-format "23.2") +(make-obsolete-variable 'default-header-line-format 'header-line-format "23.2") +(make-obsolete-variable 'default-line-spacing 'line-spacing "23.2") +(make-obsolete-variable 'default-abbrev-mode 'abbrev-mode "23.2") +(make-obsolete-variable 'default-ctl-arrow 'ctl-arrow "23.2") +(make-obsolete-variable 'default-truncate-lines 'truncate-lines "23.2") +(make-obsolete-variable 'default-left-margin 'left-margin "23.2") +(make-obsolete-variable 'default-tab-width 'tab-width "23.2") +(make-obsolete-variable 'default-case-fold-search 'case-fold-search "23.2") +(make-obsolete-variable 'default-left-margin-width 'left-margin-width "23.2") +(make-obsolete-variable 'default-right-margin-width 'right-margin-width "23.2") +(make-obsolete-variable 'default-left-fringe-width 'left-fringe-width "23.2") +(make-obsolete-variable 'default-right-fringe-width 'right-fringe-width "23.2") +(make-obsolete-variable 'default-fringes-outside-margins 'fringes-outside-margins "23.2") +(make-obsolete-variable 'default-scroll-bar-width 'scroll-bar-width "23.2") +(make-obsolete-variable 'default-vertical-scroll-bar 'vertical-scroll-bar "23.2") +(make-obsolete-variable 'default-indicate-empty-lines 'indicate-empty-lines "23.2") +(make-obsolete-variable 'default-indicate-buffer-boundaries 'indicate-buffer-boundaries "23.2") +(make-obsolete-variable 'default-fringe-indicator-alist 'fringe-indicator-alist "23.2") +(make-obsolete-variable 'default-fringe-cursor-alist 'fringe-cursor-alist "23.2") +(make-obsolete-variable 'default-scroll-up-aggressively 'scroll-up-aggressively "23.2") +(make-obsolete-variable 'default-scroll-down-aggressively 'scroll-down-aggressively "23.2") +(make-obsolete-variable 'default-fill-column 'fill-column "23.2") +(make-obsolete-variable 'default-cursor-type 'cursor-type "23.2") +(make-obsolete-variable 'default-cursor-in-non-selected-windows 'cursor-in-non-selected-windows "23.2") +(make-obsolete-variable 'default-buffer-file-coding-system 'buffer-file-coding-system "23.2") +(make-obsolete-variable 'default-major-mode 'major-mode "23.2") +(make-obsolete-variable 'default-enable-multibyte-characters + "use enable-multibyte-characters or set-buffer-multibyte instead" "23.2") + +(make-obsolete-variable 'define-key-rebound-commands nil "23.2") +(make-obsolete-variable 'redisplay-end-trigger-functions 'jit-lock-register "23.1") +(make-obsolete-variable 'deferred-action-list 'post-command-hook "24.1") +(make-obsolete-variable 'deferred-action-function 'post-command-hook "24.1") +(make-obsolete-variable 'redisplay-dont-pause nil "24.5") +(make-obsolete 'window-redisplay-end-trigger nil "23.1") +(make-obsolete 'set-window-redisplay-end-trigger nil "23.1") + +(make-obsolete 'process-filter-multibyte-p nil "23.1") +(make-obsolete 'set-process-filter-multibyte nil "23.1") + +;; Lisp manual only updated in 22.1. +(define-obsolete-variable-alias 'executing-macro 'executing-kbd-macro + "before 19.34") + +(define-obsolete-variable-alias 'x-lost-selection-hooks + 'x-lost-selection-functions "22.1") +(define-obsolete-variable-alias 'x-sent-selection-hooks + 'x-sent-selection-functions "22.1") + +;; This was introduced in 21.4 for pre-unicode unification. That +;; usage was rendered obsolete in 23.1 which uses Unicode internally. +;; Other uses are possible, so this variable is not _really_ obsolete, +;; but Stefan insists to mark it so. +(make-obsolete-variable 'translation-table-for-input nil "23.1") + +(defvaralias 'messages-buffer-max-lines 'message-log-max) + +;;;; Alternate names for functions - these are not being phased out. + +(defalias 'send-string 'process-send-string) +(defalias 'send-region 'process-send-region) +(defalias 'string= 'string-equal) +(defalias 'string< 'string-lessp) +(defalias 'move-marker 'set-marker) +(defalias 'rplaca 'setcar) +(defalias 'rplacd 'setcdr) +(defalias 'beep 'ding) ;preserve lingual purity +(defalias 'indent-to-column 'indent-to) +(defalias 'backward-delete-char 'delete-backward-char) +(defalias 'search-forward-regexp (symbol-function 're-search-forward)) +(defalias 'search-backward-regexp (symbol-function 're-search-backward)) +(defalias 'int-to-string 'number-to-string) +(defalias 'store-match-data 'set-match-data) +(defalias 'chmod 'set-file-modes) +(defalias 'mkdir 'make-directory) +;; These are the XEmacs names: +(defalias 'point-at-eol 'line-end-position) +(defalias 'point-at-bol 'line-beginning-position) + +(defalias 'user-original-login-name 'user-login-name) + + +;;;; Hook manipulation functions. + +(defun add-hook (hook function &optional append local) + "Add to the value of HOOK the function FUNCTION. +FUNCTION is not added if already present. +FUNCTION is added (if necessary) at the beginning of the hook list +unless the optional argument APPEND is non-nil, in which case +FUNCTION is added at the end. + +The optional fourth argument, LOCAL, if non-nil, says to modify +the hook's buffer-local value rather than its global value. +This makes the hook buffer-local, and it makes t a member of the +buffer-local value. That acts as a flag to run the hook +functions of the global value as well as in the local value. + +HOOK should be a symbol, and FUNCTION may be any valid function. If +HOOK is void, it is first set to nil. If HOOK's value is a single +function, it is changed to a list of functions." + (or (boundp hook) (set hook nil)) + (or (default-boundp hook) (set-default hook nil)) + (if local (unless (local-variable-if-set-p hook) + (set (make-local-variable hook) (list t))) + ;; Detect the case where make-local-variable was used on a hook + ;; and do what we used to do. + (unless (and (consp (symbol-value hook)) (memq t (symbol-value hook))) + (setq local t))) + (let ((hook-value (if local (symbol-value hook) (default-value hook)))) + ;; If the hook value is a single function, turn it into a list. + (when (or (not (listp hook-value)) (functionp hook-value)) + (setq hook-value (list hook-value))) + ;; Do the actual addition if necessary + (unless (member function hook-value) + (when (stringp function) + (setq function (purecopy function))) + (setq hook-value + (if append + (append hook-value (list function)) + (cons function hook-value)))) + ;; Set the actual variable + (if local + (progn + ;; If HOOK isn't a permanent local, + ;; but FUNCTION wants to survive a change of modes, + ;; mark HOOK as partially permanent. + (and (symbolp function) + (get function 'permanent-local-hook) + (not (get hook 'permanent-local)) + (put hook 'permanent-local 'permanent-local-hook)) + (set hook hook-value)) + (set-default hook hook-value)))) + +(defun remove-hook (hook function &optional local) + "Remove from the value of HOOK the function FUNCTION. +HOOK should be a symbol, and FUNCTION may be any valid function. If +FUNCTION isn't the value of HOOK, or, if FUNCTION doesn't appear in the +list of hooks to run in HOOK, then nothing is done. See `add-hook'. + +The optional third argument, LOCAL, if non-nil, says to modify +the hook's buffer-local value rather than its default value." + (or (boundp hook) (set hook nil)) + (or (default-boundp hook) (set-default hook nil)) + ;; Do nothing if LOCAL is t but this hook has no local binding. + (unless (and local (not (local-variable-p hook))) + ;; Detect the case where make-local-variable was used on a hook + ;; and do what we used to do. + (when (and (local-variable-p hook) + (not (and (consp (symbol-value hook)) + (memq t (symbol-value hook))))) + (setq local t)) + (let ((hook-value (if local (symbol-value hook) (default-value hook)))) + ;; Remove the function, for both the list and the non-list cases. + (if (or (not (listp hook-value)) (eq (car hook-value) 'lambda)) + (if (equal hook-value function) (setq hook-value nil)) + (setq hook-value (delete function (copy-sequence hook-value)))) + ;; If the function is on the global hook, we need to shadow it locally + ;;(when (and local (member function (default-value hook)) + ;; (not (member (cons 'not function) hook-value))) + ;; (push (cons 'not function) hook-value)) + ;; Set the actual variable + (if (not local) + (set-default hook hook-value) + (if (equal hook-value '(t)) + (kill-local-variable hook) + (set hook hook-value)))))) + +(defmacro letrec (binders &rest body) + "Bind variables according to BINDERS then eval BODY. +The value of the last form in BODY is returned. +Each element of BINDERS is a list (SYMBOL VALUEFORM) which binds +SYMBOL to the value of VALUEFORM. +All symbols are bound before the VALUEFORMs are evalled." + ;; Only useful in lexical-binding mode. + ;; As a special-form, we could implement it more efficiently (and cleanly, + ;; making the vars actually unbound during evaluation of the binders). + (declare (debug let) (indent 1)) + `(let ,(mapcar #'car binders) + ,@(mapcar (lambda (binder) `(setq ,@binder)) binders) + ,@body)) + +(defmacro with-wrapper-hook (hook args &rest body) + "Run BODY, using wrapper functions from HOOK with additional ARGS. +HOOK is an abnormal hook. Each hook function in HOOK \"wraps\" +around the preceding ones, like a set of nested `around' advices. + +Each hook function should accept an argument list consisting of a +function FUN, followed by the additional arguments in ARGS. + +The first hook function in HOOK is passed a FUN that, if it is called +with arguments ARGS, performs BODY (i.e., the default operation). +The FUN passed to each successive hook function is defined based +on the preceding hook functions; if called with arguments ARGS, +it does what the `with-wrapper-hook' call would do if the +preceding hook functions were the only ones present in HOOK. + +Each hook function may call its FUN argument as many times as it wishes, +including never. In that case, such a hook function acts to replace +the default definition altogether, and any preceding hook functions. +Of course, a subsequent hook function may do the same thing. + +Each hook function definition is used to construct the FUN passed +to the next hook function, if any. The last (or \"outermost\") +FUN is then called once." + (declare (indent 2) (debug (form sexp body)) + (obsolete "use a <foo>-function variable modified by `add-function'." + "24.4")) + ;; We need those two gensyms because CL's lexical scoping is not available + ;; for function arguments :-( + (let ((funs (make-symbol "funs")) + (global (make-symbol "global")) + (argssym (make-symbol "args")) + (runrestofhook (make-symbol "runrestofhook"))) + ;; Since the hook is a wrapper, the loop has to be done via + ;; recursion: a given hook function will call its parameter in order to + ;; continue looping. + `(letrec ((,runrestofhook + (lambda (,funs ,global ,argssym) + ;; `funs' holds the functions left on the hook and `global' + ;; holds the functions left on the global part of the hook + ;; (in case the hook is local). + (if (consp ,funs) + (if (eq t (car ,funs)) + (funcall ,runrestofhook + (append ,global (cdr ,funs)) nil ,argssym) + (apply (car ,funs) + (apply-partially + (lambda (,funs ,global &rest ,argssym) + (funcall ,runrestofhook ,funs ,global ,argssym)) + (cdr ,funs) ,global) + ,argssym)) + ;; Once there are no more functions on the hook, run + ;; the original body. + (apply (lambda ,args ,@body) ,argssym))))) + (funcall ,runrestofhook ,hook + ;; The global part of the hook, if any. + ,(if (symbolp hook) + `(if (local-variable-p ',hook) + (default-value ',hook))) + (list ,@args))))) + +(defun add-to-list (list-var element &optional append compare-fn) + "Add ELEMENT to the value of LIST-VAR if it isn't there yet. +The test for presence of ELEMENT is done with `equal', or with +COMPARE-FN if that's non-nil. +If ELEMENT is added, it is added at the beginning of the list, +unless the optional argument APPEND is non-nil, in which case +ELEMENT is added at the end. + +The return value is the new value of LIST-VAR. + +This is handy to add some elements to configuration variables, +but please do not abuse it in Elisp code, where you are usually +better off using `push' or `cl-pushnew'. + +If you want to use `add-to-list' on a variable that is not +defined until a certain package is loaded, you should put the +call to `add-to-list' into a hook function that will be run only +after loading the package. `eval-after-load' provides one way to +do this. In some cases other hooks, such as major mode hooks, +can do the job." + (declare + (compiler-macro + (lambda (exp) + ;; FIXME: Something like this could be used for `set' as well. + (if (or (not (eq 'quote (car-safe list-var))) + (special-variable-p (cadr list-var)) + (not (macroexp-const-p append))) + exp + (let* ((sym (cadr list-var)) + (append (eval append)) + (msg (format "`add-to-list' can't use lexical var `%s'; use `push' or `cl-pushnew'" + sym)) + ;; Big ugly hack so we only output a warning during + ;; byte-compilation, and so we can use + ;; byte-compile-not-lexical-var-p to silence the warning + ;; when a defvar has been seen but not yet executed. + (warnfun (lambda () + ;; FIXME: We should also emit a warning for let-bound + ;; variables with dynamic binding. + (when (assq sym byte-compile--lexical-environment) + (byte-compile-log-warning msg t :error)))) + (code + (macroexp-let2 macroexp-copyable-p x element + `(if ,(if compare-fn + (progn + (require 'cl-lib) + `(cl-member ,x ,sym :test ,compare-fn)) + ;; For bootstrapping reasons, don't rely on + ;; cl--compiler-macro-member for the base case. + `(member ,x ,sym)) + ,sym + ,(if append + `(setq ,sym (append ,sym (list ,x))) + `(push ,x ,sym)))))) + (if (not (macroexp--compiling-p)) + code + `(progn + (macroexp--funcall-if-compiled ',warnfun) + ,code))))))) + (if (cond + ((null compare-fn) + (member element (symbol-value list-var))) + ((eq compare-fn 'eq) + (memq element (symbol-value list-var))) + ((eq compare-fn 'eql) + (memql element (symbol-value list-var))) + (t + (let ((lst (symbol-value list-var))) + (while (and lst + (not (funcall compare-fn element (car lst)))) + (setq lst (cdr lst))) + lst))) + (symbol-value list-var) + (set list-var + (if append + (append (symbol-value list-var) (list element)) + (cons element (symbol-value list-var)))))) + + +(defun add-to-ordered-list (list-var element &optional order) + "Add ELEMENT to the value of LIST-VAR if it isn't there yet. +The test for presence of ELEMENT is done with `eq'. + +The resulting list is reordered so that the elements are in the +order given by each element's numeric list order. Elements +without a numeric list order are placed at the end of the list. + +If the third optional argument ORDER is a number (integer or +float), set the element's list order to the given value. If +ORDER is nil or omitted, do not change the numeric order of +ELEMENT. If ORDER has any other value, remove the numeric order +of ELEMENT if it has one. + +The list order for each element is stored in LIST-VAR's +`list-order' property. + +The return value is the new value of LIST-VAR." + (let ((ordering (get list-var 'list-order))) + (unless ordering + (put list-var 'list-order + (setq ordering (make-hash-table :weakness 'key :test 'eq)))) + (when order + (puthash element (and (numberp order) order) ordering)) + (unless (memq element (symbol-value list-var)) + (set list-var (cons element (symbol-value list-var)))) + (set list-var (sort (symbol-value list-var) + (lambda (a b) + (let ((oa (gethash a ordering)) + (ob (gethash b ordering))) + (if (and oa ob) + (< oa ob) + oa))))))) + +(defun add-to-history (history-var newelt &optional maxelt keep-all) + "Add NEWELT to the history list stored in the variable HISTORY-VAR. +Return the new history list. +If MAXELT is non-nil, it specifies the maximum length of the history. +Otherwise, the maximum history length is the value of the `history-length' +property on symbol HISTORY-VAR, if set, or the value of the `history-length' +variable. +Remove duplicates of NEWELT if `history-delete-duplicates' is non-nil. +If optional fourth arg KEEP-ALL is non-nil, add NEWELT to history even +if it is empty or a duplicate." + (unless maxelt + (setq maxelt (or (get history-var 'history-length) + history-length))) + (let ((history (symbol-value history-var)) + tail) + (when (and (listp history) + (or keep-all + (not (stringp newelt)) + (> (length newelt) 0)) + (or keep-all + (not (equal (car history) newelt)))) + (if history-delete-duplicates + (setq history (delete newelt history))) + (setq history (cons newelt history)) + (when (integerp maxelt) + (if (= 0 maxelt) + (setq history nil) + (setq tail (nthcdr (1- maxelt) history)) + (when (consp tail) + (setcdr tail nil))))) + (set history-var history))) + + +;;;; Mode hooks. + +(defvar delay-mode-hooks nil + "If non-nil, `run-mode-hooks' should delay running the hooks.") +(defvar delayed-mode-hooks nil + "List of delayed mode hooks waiting to be run.") +(make-variable-buffer-local 'delayed-mode-hooks) +(put 'delay-mode-hooks 'permanent-local t) + +(defvar change-major-mode-after-body-hook nil + "Normal hook run in major mode functions, before the mode hooks.") + +(defvar after-change-major-mode-hook nil + "Normal hook run at the very end of major mode functions.") + +(defun run-mode-hooks (&rest hooks) + "Run mode hooks `delayed-mode-hooks' and HOOKS, or delay HOOKS. +If the variable `delay-mode-hooks' is non-nil, does not run any hooks, +just adds the HOOKS to the list `delayed-mode-hooks'. +Otherwise, runs hooks in the sequence: `change-major-mode-after-body-hook', +`delayed-mode-hooks' (in reverse order), HOOKS, and finally +`after-change-major-mode-hook'. Major mode functions should use +this instead of `run-hooks' when running their FOO-mode-hook." + (if delay-mode-hooks + ;; Delaying case. + (dolist (hook hooks) + (push hook delayed-mode-hooks)) + ;; Normal case, just run the hook as before plus any delayed hooks. + (setq hooks (nconc (nreverse delayed-mode-hooks) hooks)) + (setq delayed-mode-hooks nil) + (apply 'run-hooks (cons 'change-major-mode-after-body-hook hooks)) + (run-hooks 'after-change-major-mode-hook))) + +(defmacro delay-mode-hooks (&rest body) + "Execute BODY, but delay any `run-mode-hooks'. +These hooks will be executed by the first following call to +`run-mode-hooks' that occurs outside any `delayed-mode-hooks' form. +Only affects hooks run in the current buffer." + (declare (debug t) (indent 0)) + `(progn + (make-local-variable 'delay-mode-hooks) + (let ((delay-mode-hooks t)) + ,@body))) + +;; PUBLIC: find if the current mode derives from another. + +(defun derived-mode-p (&rest modes) + "Non-nil if the current major mode is derived from one of MODES. +Uses the `derived-mode-parent' property of the symbol to trace backwards." + (let ((parent major-mode)) + (while (and (not (memq parent modes)) + (setq parent (get parent 'derived-mode-parent)))) + parent)) + +;;;; Minor modes. + +;; If a minor mode is not defined with define-minor-mode, +;; add it here explicitly. +;; isearch-mode is deliberately excluded, since you should +;; not call it yourself. +(defvar minor-mode-list '(auto-save-mode auto-fill-mode abbrev-mode + overwrite-mode view-mode + hs-minor-mode) + "List of all minor mode functions.") + +(defun add-minor-mode (toggle name &optional keymap after toggle-fun) + "Register a new minor mode. + +This is an XEmacs-compatibility function. Use `define-minor-mode' instead. + +TOGGLE is a symbol which is the name of a buffer-local variable that +is toggled on or off to say whether the minor mode is active or not. + +NAME specifies what will appear in the mode line when the minor mode +is active. NAME should be either a string starting with a space, or a +symbol whose value is such a string. + +Optional KEYMAP is the keymap for the minor mode that will be added +to `minor-mode-map-alist'. + +Optional AFTER specifies that TOGGLE should be added after AFTER +in `minor-mode-alist'. + +Optional TOGGLE-FUN is an interactive function to toggle the mode. +It defaults to (and should by convention be) TOGGLE. + +If TOGGLE has a non-nil `:included' property, an entry for the mode is +included in the mode-line minor mode menu. +If TOGGLE has a `:menu-tag', that is used for the menu item's label." + (unless (memq toggle minor-mode-list) + (push toggle minor-mode-list)) + + (unless toggle-fun (setq toggle-fun toggle)) + (unless (eq toggle-fun toggle) + (put toggle :minor-mode-function toggle-fun)) + ;; Add the name to the minor-mode-alist. + (when name + (let ((existing (assq toggle minor-mode-alist))) + (if existing + (setcdr existing (list name)) + (let ((tail minor-mode-alist) found) + (while (and tail (not found)) + (if (eq after (caar tail)) + (setq found tail) + (setq tail (cdr tail)))) + (if found + (let ((rest (cdr found))) + (setcdr found nil) + (nconc found (list (list toggle name)) rest)) + (push (list toggle name) minor-mode-alist)))))) + ;; Add the toggle to the minor-modes menu if requested. + (when (get toggle :included) + (define-key mode-line-mode-menu + (vector toggle) + (list 'menu-item + (concat + (or (get toggle :menu-tag) + (if (stringp name) name (symbol-name toggle))) + (let ((mode-name (if (symbolp name) (symbol-value name)))) + (if (and (stringp mode-name) (string-match "[^ ]+" mode-name)) + (concat " (" (match-string 0 mode-name) ")")))) + toggle-fun + :button (cons :toggle toggle)))) + + ;; Add the map to the minor-mode-map-alist. + (when keymap + (let ((existing (assq toggle minor-mode-map-alist))) + (if existing + (setcdr existing keymap) + (let ((tail minor-mode-map-alist) found) + (while (and tail (not found)) + (if (eq after (caar tail)) + (setq found tail) + (setq tail (cdr tail)))) + (if found + (let ((rest (cdr found))) + (setcdr found nil) + (nconc found (list (cons toggle keymap)) rest)) + (push (cons toggle keymap) minor-mode-map-alist))))))) + +;;;; Load history + +(defsubst autoloadp (object) + "Non-nil if OBJECT is an autoload." + (eq 'autoload (car-safe object))) + +;; (defun autoload-type (object) +;; "Returns the type of OBJECT or `function' or `command' if the type is nil. +;; OBJECT should be an autoload object." +;; (when (autoloadp object) +;; (let ((type (nth 3 object))) +;; (cond ((null type) (if (nth 2 object) 'command 'function)) +;; ((eq 'keymap t) 'macro) +;; (type))))) + +;; (defalias 'autoload-file #'cadr +;; "Return the name of the file from which AUTOLOAD will be loaded. +;; \n\(fn AUTOLOAD)") + +(defun symbol-file (symbol &optional type) + "Return the name of the file that defined SYMBOL. +The value is normally an absolute file name. It can also be nil, +if the definition is not associated with any file. If SYMBOL +specifies an autoloaded function, the value can be a relative +file name without extension. + +If TYPE is nil, then any kind of definition is acceptable. If +TYPE is `defun', `defvar', or `defface', that specifies function +definition, variable definition, or face definition only." + (if (and (or (null type) (eq type 'defun)) + (symbolp symbol) + (autoloadp (symbol-function symbol))) + (nth 1 (symbol-function symbol)) + (let ((files load-history) + file) + (while files + (if (if type + (if (eq type 'defvar) + ;; Variables are present just as their names. + (member symbol (cdr (car files))) + ;; Other types are represented as (TYPE . NAME). + (member (cons type symbol) (cdr (car files)))) + ;; We accept all types, so look for variable def + ;; and then for any other kind. + (or (member symbol (cdr (car files))) + (rassq symbol (cdr (car files))))) + (setq file (car (car files)) files nil)) + (setq files (cdr files))) + file))) + +(defun locate-library (library &optional nosuffix path interactive-call) + "Show the precise file name of Emacs library LIBRARY. +LIBRARY should be a relative file name of the library, a string. +It can omit the suffix (a.k.a. file-name extension) if NOSUFFIX is +nil (which is the default, see below). +This command searches the directories in `load-path' like `\\[load-library]' +to find the file that `\\[load-library] RET LIBRARY RET' would load. +Optional second arg NOSUFFIX non-nil means don't add suffixes `load-suffixes' +to the specified name LIBRARY. + +If the optional third arg PATH is specified, that list of directories +is used instead of `load-path'. + +When called from a program, the file name is normally returned as a +string. When run interactively, the argument INTERACTIVE-CALL is t, +and the file name is displayed in the echo area." + (interactive (list (completing-read "Locate library: " + (apply-partially + 'locate-file-completion-table + load-path (get-load-suffixes))) + nil nil + t)) + (let ((file (locate-file library + (or path load-path) + (append (unless nosuffix (get-load-suffixes)) + load-file-rep-suffixes)))) + (if interactive-call + (if file + (message "Library is file %s" (abbreviate-file-name file)) + (message "No library %s in search path" library))) + file)) + + +;;;; Process stuff. + +(defun process-lines (program &rest args) + "Execute PROGRAM with ARGS, returning its output as a list of lines. +Signal an error if the program returns with a non-zero exit status." + (with-temp-buffer + (let ((status (apply 'call-process program nil (current-buffer) nil args))) + (unless (eq status 0) + (error "%s exited with status %s" program status)) + (goto-char (point-min)) + (let (lines) + (while (not (eobp)) + (setq lines (cons (buffer-substring-no-properties + (line-beginning-position) + (line-end-position)) + lines)) + (forward-line 1)) + (nreverse lines))))) + +(defun process-live-p (process) + "Returns non-nil if PROCESS is alive. +A process is considered alive if its status is `run', `open', +`listen', `connect' or `stop'. Value is nil if PROCESS is not a +process." + (and (processp process) + (memq (process-status process) + '(run open listen connect stop)))) + +;; compatibility + +(make-obsolete + 'process-kill-without-query + "use `process-query-on-exit-flag' or `set-process-query-on-exit-flag'." + "22.1") +(defun process-kill-without-query (process &optional _flag) + "Say no query needed if PROCESS is running when Emacs is exited. +Optional second argument if non-nil says to require a query. +Value is t if a query was formerly required." + (let ((old (process-query-on-exit-flag process))) + (set-process-query-on-exit-flag process nil) + old)) + +(defun process-kill-buffer-query-function () + "Ask before killing a buffer that has a running process." + (let ((process (get-buffer-process (current-buffer)))) + (or (not process) + (not (memq (process-status process) '(run stop open listen))) + (not (process-query-on-exit-flag process)) + (yes-or-no-p + (format "Buffer %S has a running process; kill it? " + (buffer-name (current-buffer))))))) + +(add-hook 'kill-buffer-query-functions 'process-kill-buffer-query-function) + +;; process plist management + +(defun process-get (process propname) + "Return the value of PROCESS' PROPNAME property. +This is the last value stored with `(process-put PROCESS PROPNAME VALUE)'." + (plist-get (process-plist process) propname)) + +(defun process-put (process propname value) + "Change PROCESS' PROPNAME property to VALUE. +It can be retrieved with `(process-get PROCESS PROPNAME)'." + (set-process-plist process + (plist-put (process-plist process) propname value))) + + +;;;; Input and display facilities. + +(defconst read-key-empty-map (make-sparse-keymap)) + +(defvar read-key-delay 0.01) ;Fast enough for 100Hz repeat rate, hopefully. + +(defun read-key (&optional prompt) + "Read a key from the keyboard. +Contrary to `read-event' this will not return a raw event but instead will +obey the input decoding and translations usually done by `read-key-sequence'. +So escape sequences and keyboard encoding are taken into account. +When there's an ambiguity because the key looks like the prefix of +some sort of escape sequence, the ambiguity is resolved via `read-key-delay'." + ;; This overriding-terminal-local-map binding also happens to + ;; disable quail's input methods, so although read-key-sequence + ;; always inherits the input method, in practice read-key does not + ;; inherit the input method (at least not if it's based on quail). + (let ((overriding-terminal-local-map nil) + (overriding-local-map read-key-empty-map) + (echo-keystrokes 0) + (old-global-map (current-global-map)) + (timer (run-with-idle-timer + ;; Wait long enough that Emacs has the time to receive and + ;; process all the raw events associated with the single-key. + ;; But don't wait too long, or the user may find the delay + ;; annoying (or keep hitting more keys which may then get + ;; lost or misinterpreted). + ;; This is only relevant for keys which Emacs perceives as + ;; "prefixes", such as C-x (because of the C-x 8 map in + ;; key-translate-table and the C-x @ map in function-key-map) + ;; or ESC (because of terminal escape sequences in + ;; input-decode-map). + read-key-delay t + (lambda () + (let ((keys (this-command-keys-vector))) + (unless (zerop (length keys)) + ;; `keys' is non-empty, so the user has hit at least + ;; one key; there's no point waiting any longer, even + ;; though read-key-sequence thinks we should wait + ;; for more input to decide how to interpret the + ;; current input. + (throw 'read-key keys))))))) + (unwind-protect + (progn + (use-global-map + (let ((map (make-sparse-keymap))) + ;; Don't hide the menu-bar and tool-bar entries. + (define-key map [menu-bar] (lookup-key global-map [menu-bar])) + (define-key map [tool-bar] + ;; This hack avoids evaluating the :filter (Bug#9922). + (or (cdr (assq 'tool-bar global-map)) + (lookup-key global-map [tool-bar]))) + map)) + (let* ((keys + (catch 'read-key (read-key-sequence-vector prompt nil t))) + (key (aref keys 0))) + (if (and (> (length keys) 1) + (memq key '(mode-line header-line + left-fringe right-fringe))) + (aref keys 1) + key))) + (cancel-timer timer) + (use-global-map old-global-map)))) + +(defvar read-passwd-map + ;; BEWARE: `defconst' would purecopy it, breaking the sharing with + ;; minibuffer-local-map along the way! + (let ((map (make-sparse-keymap))) + (set-keymap-parent map minibuffer-local-map) + (define-key map "\C-u" #'delete-minibuffer-contents) ;bug#12570 + map) + "Keymap used while reading passwords.") + +(defun read-passwd (prompt &optional confirm default) + "Read a password, prompting with PROMPT, and return it. +If optional CONFIRM is non-nil, read the password twice to make sure. +Optional DEFAULT is a default password to use instead of empty input. + +This function echoes `.' for each character that the user types. +You could let-bind `read-hide-char' to another hiding character, though. + +Once the caller uses the password, it can erase the password +by doing (clear-string STRING)." + (if confirm + (let (success) + (while (not success) + (let ((first (read-passwd prompt nil default)) + (second (read-passwd "Confirm password: " nil default))) + (if (equal first second) + (progn + (and (arrayp second) (clear-string second)) + (setq success first)) + (and (arrayp first) (clear-string first)) + (and (arrayp second) (clear-string second)) + (message "Password not repeated accurately; please start over") + (sit-for 1)))) + success) + (let ((hide-chars-fun + (lambda (beg end _len) + (clear-this-command-keys) + (setq beg (min end (max (minibuffer-prompt-end) + beg))) + (dotimes (i (- end beg)) + (put-text-property (+ i beg) (+ 1 i beg) + 'display (string (or read-hide-char ?.)))))) + minibuf) + (minibuffer-with-setup-hook + (lambda () + (setq minibuf (current-buffer)) + ;; Turn off electricity. + (setq-local post-self-insert-hook nil) + (setq-local buffer-undo-list t) + (setq-local select-active-regions nil) + (use-local-map read-passwd-map) + (setq-local inhibit-modification-hooks nil) ;bug#15501. + (setq-local show-paren-mode nil) ;bug#16091. + (add-hook 'after-change-functions hide-chars-fun nil 'local)) + (unwind-protect + (let ((enable-recursive-minibuffers t) + (read-hide-char (or read-hide-char ?.))) + (read-string prompt nil t default)) ; t = "no history" + (when (buffer-live-p minibuf) + (with-current-buffer minibuf + ;; Not sure why but it seems that there might be cases where the + ;; minibuffer is not always properly reset later on, so undo + ;; whatever we've done here (bug#11392). + (remove-hook 'after-change-functions hide-chars-fun 'local) + (kill-local-variable 'post-self-insert-hook) + ;; And of course, don't keep the sensitive data around. + (erase-buffer)))))))) + +(defun read-number (prompt &optional default) + "Read a numeric value in the minibuffer, prompting with PROMPT. +DEFAULT specifies a default value to return if the user just types RET. +The value of DEFAULT is inserted into PROMPT. +This function is used by the `interactive' code letter `n'." + (let ((n nil) + (default1 (if (consp default) (car default) default))) + (when default1 + (setq prompt + (if (string-match "\\(\\):[ \t]*\\'" prompt) + (replace-match (format " (default %s)" default1) t t prompt 1) + (replace-regexp-in-string "[ \t]*\\'" + (format " (default %s) " default1) + prompt t t)))) + (while + (progn + (let ((str (read-from-minibuffer + prompt nil nil nil nil + (when default + (if (consp default) + (mapcar 'number-to-string (delq nil default)) + (number-to-string default)))))) + (condition-case nil + (setq n (cond + ((zerop (length str)) default1) + ((stringp str) (read str)))) + (error nil))) + (unless (numberp n) + (message "Please enter a number.") + (sit-for 1) + t))) + n)) + +(defun read-char-choice (prompt chars &optional inhibit-keyboard-quit) + "Read and return one of CHARS, prompting for PROMPT. +Any input that is not one of CHARS is ignored. + +If optional argument INHIBIT-KEYBOARD-QUIT is non-nil, ignore +keyboard-quit events while waiting for a valid input." + (unless (consp chars) + (error "Called `read-char-choice' without valid char choices")) + (let (char done show-help (helpbuf " *Char Help*")) + (let ((cursor-in-echo-area t) + (executing-kbd-macro executing-kbd-macro) + (esc-flag nil)) + (save-window-excursion ; in case we call help-form-show + (while (not done) + (unless (get-text-property 0 'face prompt) + (setq prompt (propertize prompt 'face 'minibuffer-prompt))) + (setq char (let ((inhibit-quit inhibit-keyboard-quit)) + (read-key prompt))) + (and show-help (buffer-live-p (get-buffer helpbuf)) + (kill-buffer helpbuf)) + (cond + ((not (numberp char))) + ;; If caller has set help-form, that's enough. + ;; They don't explicitly have to add help-char to chars. + ((and help-form + (eq char help-char) + (setq show-help t) + (help-form-show))) + ((memq char chars) + (setq done t)) + ((and executing-kbd-macro (= char -1)) + ;; read-event returns -1 if we are in a kbd macro and + ;; there are no more events in the macro. Attempt to + ;; get an event interactively. + (setq executing-kbd-macro nil)) + ((not inhibit-keyboard-quit) + (cond + ((and (null esc-flag) (eq char ?\e)) + (setq esc-flag t)) + ((memq char '(?\C-g ?\e)) + (keyboard-quit)))))))) + ;; Display the question with the answer. But without cursor-in-echo-area. + (message "%s%s" prompt (char-to-string char)) + char)) + +(defun sit-for (seconds &optional nodisp obsolete) + "Redisplay, then wait for SECONDS seconds. Stop when input is available. +SECONDS may be a floating-point value. +\(On operating systems that do not support waiting for fractions of a +second, floating-point values are rounded down to the nearest integer.) + +If optional arg NODISP is t, don't redisplay, just wait for input. +Redisplay does not happen if input is available before it starts. + +Value is t if waited the full time with no input arriving, and nil otherwise. + +An obsolete, but still supported form is +\(sit-for SECONDS &optional MILLISECONDS NODISP) +where the optional arg MILLISECONDS specifies an additional wait period, +in milliseconds; this was useful when Emacs was built without +floating point support." + (declare (advertised-calling-convention (seconds &optional nodisp) "22.1")) + ;; This used to be implemented in C until the following discussion: + ;; http://lists.gnu.org/archive/html/emacs-devel/2006-07/msg00401.html + ;; Then it was moved here using an implementation based on an idle timer, + ;; which was then replaced by the use of read-event. + (if (numberp nodisp) + (setq seconds (+ seconds (* 1e-3 nodisp)) + nodisp obsolete) + (if obsolete (setq nodisp obsolete))) + (cond + (noninteractive + (sleep-for seconds) + t) + ((input-pending-p t) + nil) + ((<= seconds 0) + (or nodisp (redisplay))) + (t + (or nodisp (redisplay)) + ;; FIXME: we should not read-event here at all, because it's much too + ;; difficult to reliably "undo" a read-event by pushing it onto + ;; unread-command-events. + ;; For bug#14782, we need read-event to do the keyboard-coding-system + ;; decoding (hence non-nil as second arg under POSIX ttys). + ;; For bug#15614, we need read-event not to inherit-input-method. + ;; So we temporarily suspend input-method-function. + (let ((read (let ((input-method-function nil)) + (read-event nil t seconds)))) + (or (null read) + (progn + ;; https://lists.gnu.org/archive/html/emacs-devel/2006-10/msg00394.html + ;; We want `read' appear in the next command's this-command-event + ;; but not in the current one. + ;; By pushing (cons t read), we indicate that `read' has not + ;; yet been recorded in this-command-keys, so it will be recorded + ;; next time it's read. + ;; And indeed the `seconds' argument to read-event correctly + ;; prevented recording this event in the current command's + ;; this-command-keys. + (push (cons t read) unread-command-events) + nil)))))) + +;; Behind display-popup-menus-p test. +(declare-function x-popup-dialog "menu.c" (position contents &optional header)) + +(defun y-or-n-p (prompt) + "Ask user a \"y or n\" question. Return t if answer is \"y\". +PROMPT is the string to display to ask the question. It should +end in a space; `y-or-n-p' adds \"(y or n) \" to it. + +No confirmation of the answer is requested; a single character is +enough. SPC also means yes, and DEL means no. + +To be precise, this function translates user input into responses +by consulting the bindings in `query-replace-map'; see the +documentation of that variable for more information. In this +case, the useful bindings are `act', `skip', `recenter', +`scroll-up', `scroll-down', and `quit'. +An `act' response means yes, and a `skip' response means no. +A `quit' response means to invoke `keyboard-quit'. +If the user enters `recenter', `scroll-up', or `scroll-down' +responses, perform the requested window recentering or scrolling +and ask again. + +Under a windowing system a dialog box will be used if `last-nonmenu-event' +is nil and `use-dialog-box' is non-nil." + ;; ¡Beware! when I tried to edebug this code, Emacs got into a weird state + ;; where all the keys were unbound (i.e. it somehow got triggered + ;; within read-key, apparently). I had to kill it. + (let ((answer 'recenter) + (padded (lambda (prompt &optional dialog) + (let ((l (length prompt))) + (concat prompt + (if (or (zerop l) (eq ?\s (aref prompt (1- l)))) + "" " ") + (if dialog "" "(y or n) ")))))) + (cond + (noninteractive + (setq prompt (funcall padded prompt)) + (let ((temp-prompt prompt)) + (while (not (memq answer '(act skip))) + (let ((str (read-string temp-prompt))) + (cond ((member str '("y" "Y")) (setq answer 'act)) + ((member str '("n" "N")) (setq answer 'skip)) + (t (setq temp-prompt (concat "Please answer y or n. " + prompt)))))))) + ((and (display-popup-menus-p) + (listp last-nonmenu-event) + use-dialog-box) + (setq prompt (funcall padded prompt t) + answer (x-popup-dialog t `(,prompt ("Yes" . act) ("No" . skip))))) + (t + (setq prompt (funcall padded prompt)) + (while + (let* ((scroll-actions '(recenter scroll-up scroll-down + scroll-other-window scroll-other-window-down)) + (key + (let ((cursor-in-echo-area t)) + (when minibuffer-auto-raise + (raise-frame (window-frame (minibuffer-window)))) + (read-key (propertize (if (memq answer scroll-actions) + prompt + (concat "Please answer y or n. " + prompt)) + 'face 'minibuffer-prompt))))) + (setq answer (lookup-key query-replace-map (vector key) t)) + (cond + ((memq answer '(skip act)) nil) + ((eq answer 'recenter) + (recenter) t) + ((eq answer 'scroll-up) + (ignore-errors (scroll-up-command)) t) + ((eq answer 'scroll-down) + (ignore-errors (scroll-down-command)) t) + ((eq answer 'scroll-other-window) + (ignore-errors (scroll-other-window)) t) + ((eq answer 'scroll-other-window-down) + (ignore-errors (scroll-other-window-down)) t) + ((or (memq answer '(exit-prefix quit)) (eq key ?\e)) + (signal 'quit nil) t) + (t t))) + (ding) + (discard-input)))) + (let ((ret (eq answer 'act))) + (unless noninteractive + (message "%s%c" prompt (if ret ?y ?n))) + ret))) + + +;;; Atomic change groups. + +(defmacro atomic-change-group (&rest body) + "Perform BODY as an atomic change group. +This means that if BODY exits abnormally, +all of its changes to the current buffer are undone. +This works regardless of whether undo is enabled in the buffer. + +This mechanism is transparent to ordinary use of undo; +if undo is enabled in the buffer and BODY succeeds, the +user can undo the change normally." + (declare (indent 0) (debug t)) + (let ((handle (make-symbol "--change-group-handle--")) + (success (make-symbol "--change-group-success--"))) + `(let ((,handle (prepare-change-group)) + ;; Don't truncate any undo data in the middle of this. + (undo-outer-limit nil) + (undo-limit most-positive-fixnum) + (undo-strong-limit most-positive-fixnum) + (,success nil)) + (unwind-protect + (progn + ;; This is inside the unwind-protect because + ;; it enables undo if that was disabled; we need + ;; to make sure that it gets disabled again. + (activate-change-group ,handle) + ,@body + (setq ,success t)) + ;; Either of these functions will disable undo + ;; if it was disabled before. + (if ,success + (accept-change-group ,handle) + (cancel-change-group ,handle)))))) + +(defun prepare-change-group (&optional buffer) + "Return a handle for the current buffer's state, for a change group. +If you specify BUFFER, make a handle for BUFFER's state instead. + +Pass the handle to `activate-change-group' afterward to initiate +the actual changes of the change group. + +To finish the change group, call either `accept-change-group' or +`cancel-change-group' passing the same handle as argument. Call +`accept-change-group' to accept the changes in the group as final; +call `cancel-change-group' to undo them all. You should use +`unwind-protect' to make sure the group is always finished. The call +to `activate-change-group' should be inside the `unwind-protect'. +Once you finish the group, don't use the handle again--don't try to +finish the same group twice. For a simple example of correct use, see +the source code of `atomic-change-group'. + +The handle records only the specified buffer. To make a multibuffer +change group, call this function once for each buffer you want to +cover, then use `nconc' to combine the returned values, like this: + + (nconc (prepare-change-group buffer-1) + (prepare-change-group buffer-2)) + +You can then activate that multibuffer change group with a single +call to `activate-change-group' and finish it with a single call +to `accept-change-group' or `cancel-change-group'." + + (if buffer + (list (cons buffer (with-current-buffer buffer buffer-undo-list))) + (list (cons (current-buffer) buffer-undo-list)))) + +(defun activate-change-group (handle) + "Activate a change group made with `prepare-change-group' (which see)." + (dolist (elt handle) + (with-current-buffer (car elt) + (if (eq buffer-undo-list t) + (setq buffer-undo-list nil))))) + +(defun accept-change-group (handle) + "Finish a change group made with `prepare-change-group' (which see). +This finishes the change group by accepting its changes as final." + (dolist (elt handle) + (with-current-buffer (car elt) + (if (eq (cdr elt) t) + (setq buffer-undo-list t))))) + +(defun cancel-change-group (handle) + "Finish a change group made with `prepare-change-group' (which see). +This finishes the change group by reverting all of its changes." + (dolist (elt handle) + (with-current-buffer (car elt) + (setq elt (cdr elt)) + (save-restriction + ;; Widen buffer temporarily so if the buffer was narrowed within + ;; the body of `atomic-change-group' all changes can be undone. + (widen) + (let ((old-car + (if (consp elt) (car elt))) + (old-cdr + (if (consp elt) (cdr elt)))) + ;; Temporarily truncate the undo log at ELT. + (when (consp elt) + (setcar elt nil) (setcdr elt nil)) + (unless (eq last-command 'undo) (undo-start)) + ;; Make sure there's no confusion. + (when (and (consp elt) (not (eq elt (last pending-undo-list)))) + (error "Undoing to some unrelated state")) + ;; Undo it all. + (save-excursion + (while (listp pending-undo-list) (undo-more 1))) + ;; Reset the modified cons cell ELT to its original content. + (when (consp elt) + (setcar elt old-car) + (setcdr elt old-cdr)) + ;; Revert the undo info to what it was when we grabbed the state. + (setq buffer-undo-list elt)))))) + +;;;; Display-related functions. + +;; For compatibility. +(define-obsolete-function-alias 'redraw-modeline + 'force-mode-line-update "24.3") + +(defun momentary-string-display (string pos &optional exit-char message) + "Momentarily display STRING in the buffer at POS. +Display remains until next event is input. +If POS is a marker, only its position is used; its buffer is ignored. +Optional third arg EXIT-CHAR can be a character, event or event +description list. EXIT-CHAR defaults to SPC. If the input is +EXIT-CHAR it is swallowed; otherwise it is then available as +input (as a command if nothing else). +Display MESSAGE (optional fourth arg) in the echo area. +If MESSAGE is nil, instructions to type EXIT-CHAR are displayed there." + (or exit-char (setq exit-char ?\s)) + (let ((ol (make-overlay pos pos)) + (str (copy-sequence string))) + (unwind-protect + (progn + (save-excursion + (overlay-put ol 'after-string str) + (goto-char pos) + ;; To avoid trouble with out-of-bounds position + (setq pos (point)) + ;; If the string end is off screen, recenter now. + (if (<= (window-end nil t) pos) + (recenter (/ (window-height) 2)))) + (message (or message "Type %s to continue editing.") + (single-key-description exit-char)) + (let ((event (read-key))) + ;; `exit-char' can be an event, or an event description list. + (or (eq event exit-char) + (eq event (event-convert-list exit-char)) + (setq unread-command-events + (append (this-single-command-raw-keys)))))) + (delete-overlay ol)))) + + +;;;; Overlay operations + +(defun copy-overlay (o) + "Return a copy of overlay O." + (let ((o1 (if (overlay-buffer o) + (make-overlay (overlay-start o) (overlay-end o) + ;; FIXME: there's no easy way to find the + ;; insertion-type of the two markers. + (overlay-buffer o)) + (let ((o1 (make-overlay (point-min) (point-min)))) + (delete-overlay o1) + o1))) + (props (overlay-properties o))) + (while props + (overlay-put o1 (pop props) (pop props))) + o1)) + +(defun remove-overlays (&optional beg end name val) + "Clear BEG and END of overlays whose property NAME has value VAL. +Overlays might be moved and/or split. +BEG and END default respectively to the beginning and end of buffer." + ;; This speeds up the loops over overlays. + (unless beg (setq beg (point-min))) + (unless end (setq end (point-max))) + (overlay-recenter end) + (if (< end beg) + (setq beg (prog1 end (setq end beg)))) + (save-excursion + (dolist (o (overlays-in beg end)) + (when (eq (overlay-get o name) val) + ;; Either push this overlay outside beg...end + ;; or split it to exclude beg...end + ;; or delete it entirely (if it is contained in beg...end). + (if (< (overlay-start o) beg) + (if (> (overlay-end o) end) + (progn + (move-overlay (copy-overlay o) + (overlay-start o) beg) + (move-overlay o end (overlay-end o))) + (move-overlay o (overlay-start o) beg)) + (if (> (overlay-end o) end) + (move-overlay o end (overlay-end o)) + (delete-overlay o))))))) + +;;;; Miscellanea. + +(defvar suspend-hook nil + "Normal hook run by `suspend-emacs', before suspending.") + +(defvar suspend-resume-hook nil + "Normal hook run by `suspend-emacs', after Emacs is continued.") + +(defvar temp-buffer-show-hook nil + "Normal hook run by `with-output-to-temp-buffer' after displaying the buffer. +When the hook runs, the temporary buffer is current, and the window it +was displayed in is selected.") + +(defvar temp-buffer-setup-hook nil + "Normal hook run by `with-output-to-temp-buffer' at the start. +When the hook runs, the temporary buffer is current. +This hook is normally set up with a function to put the buffer in Help +mode.") + +(defconst user-emacs-directory + (if (eq system-type 'ms-dos) + ;; MS-DOS cannot have initial dot. + "~/_emacs.d/" + "~/.emacs.d/") + "Directory beneath which additional per-user Emacs-specific files are placed. +Various programs in Emacs store information in this directory. +Note that this should end with a directory separator. +See also `locate-user-emacs-file'.") + +;;;; Misc. useful functions. + +(defsubst buffer-narrowed-p () + "Return non-nil if the current buffer is narrowed." + (/= (- (point-max) (point-min)) (buffer-size))) + +(defun find-tag-default-bounds () + "Determine the boundaries of the default tag, based on text at point. +Return a cons cell with the beginning and end of the found tag. +If there is no plausible default, return nil." + (let (from to bound) + (when (or (progn + ;; Look at text around `point'. + (save-excursion + (skip-syntax-backward "w_") (setq from (point))) + (save-excursion + (skip-syntax-forward "w_") (setq to (point))) + (> to from)) + ;; Look between `line-beginning-position' and `point'. + (save-excursion + (and (setq bound (line-beginning-position)) + (skip-syntax-backward "^w_" bound) + (> (setq to (point)) bound) + (skip-syntax-backward "w_") + (setq from (point)))) + ;; Look between `point' and `line-end-position'. + (save-excursion + (and (setq bound (line-end-position)) + (skip-syntax-forward "^w_" bound) + (< (setq from (point)) bound) + (skip-syntax-forward "w_") + (setq to (point))))) + (cons from to)))) + +(defun find-tag-default () + "Determine default tag to search for, based on text at point. +If there is no plausible default, return nil." + (let ((bounds (find-tag-default-bounds))) + (when bounds + (buffer-substring-no-properties (car bounds) (cdr bounds))))) + +(defun find-tag-default-as-regexp () + "Return regexp that matches the default tag at point. +If there is no tag at point, return nil. + +When in a major mode that does not provide its own +`find-tag-default-function', return a regexp that matches the +symbol at point exactly." + (let ((tag (funcall (or find-tag-default-function + (get major-mode 'find-tag-default-function) + 'find-tag-default)))) + (if tag (regexp-quote tag)))) + +(defun find-tag-default-as-symbol-regexp () + "Return regexp that matches the default tag at point as symbol. +If there is no tag at point, return nil. + +When in a major mode that does not provide its own +`find-tag-default-function', return a regexp that matches the +symbol at point exactly." + (let ((tag-regexp (find-tag-default-as-regexp))) + (if (and tag-regexp + (eq (or find-tag-default-function + (get major-mode 'find-tag-default-function) + 'find-tag-default) + 'find-tag-default)) + (format "\\_<%s\\_>" tag-regexp) + tag-regexp))) + +(defun play-sound (sound) + "SOUND is a list of the form `(sound KEYWORD VALUE...)'. +The following keywords are recognized: + + :file FILE - read sound data from FILE. If FILE isn't an +absolute file name, it is searched in `data-directory'. + + :data DATA - read sound data from string DATA. + +Exactly one of :file or :data must be present. + + :volume VOL - set volume to VOL. VOL must an integer in the +range 0..100 or a float in the range 0..1.0. If not specified, +don't change the volume setting of the sound device. + + :device DEVICE - play sound on DEVICE. If not specified, +a system-dependent default device name is used. + +Note: :data and :device are currently not supported on Windows." + (if (fboundp 'play-sound-internal) + (play-sound-internal sound) + (error "This Emacs binary lacks sound support"))) + +(declare-function w32-shell-dos-semantics "w32-fns" nil) + +(defun shell-quote-argument (argument) + "Quote ARGUMENT for passing as argument to an inferior shell." + (cond + ((eq system-type 'ms-dos) + ;; Quote using double quotes, but escape any existing quotes in + ;; the argument with backslashes. + (let ((result "") + (start 0) + end) + (if (or (null (string-match "[^\"]" argument)) + (< (match-end 0) (length argument))) + (while (string-match "[\"]" argument start) + (setq end (match-beginning 0) + result (concat result (substring argument start end) + "\\" (substring argument end (1+ end))) + start (1+ end)))) + (concat "\"" result (substring argument start) "\""))) + + ((and (eq system-type 'windows-nt) (w32-shell-dos-semantics)) + + ;; First, quote argument so that CommandLineToArgvW will + ;; understand it. See + ;; http://msdn.microsoft.com/en-us/library/17w5ykft%28v=vs.85%29.aspx + ;; After we perform that level of quoting, escape shell + ;; metacharacters so that cmd won't mangle our argument. If the + ;; argument contains no double quote characters, we can just + ;; surround it with double quotes. Otherwise, we need to prefix + ;; each shell metacharacter with a caret. + + (setq argument + ;; escape backslashes at end of string + (replace-regexp-in-string + "\\(\\\\*\\)$" + "\\1\\1" + ;; escape backslashes and quotes in string body + (replace-regexp-in-string + "\\(\\\\*\\)\"" + "\\1\\1\\\\\"" + argument))) + + (if (string-match "[%!\"]" argument) + (concat + "^\"" + (replace-regexp-in-string + "\\([%!()\"<>&|^]\\)" + "^\\1" + argument) + "^\"") + (concat "\"" argument "\""))) + + (t + (if (equal argument "") + "''" + ;; Quote everything except POSIX filename characters. + ;; This should be safe enough even for really weird shells. + (replace-regexp-in-string + "\n" "'\n'" + (replace-regexp-in-string "[^-0-9a-zA-Z_./\n]" "\\\\\\&" argument)))) + )) + +(defun string-or-null-p (object) + "Return t if OBJECT is a string or nil. +Otherwise, return nil." + (or (stringp object) (null object))) + +(defun booleanp (object) + "Return t if OBJECT is one of the two canonical boolean values: t or nil. +Otherwise, return nil." + (and (memq object '(nil t)) t)) + +(defun special-form-p (object) + "Non-nil if and only if OBJECT is a special form." + (if (and (symbolp object) (fboundp object)) + (setq object (indirect-function object t))) + (and (subrp object) (eq (cdr (subr-arity object)) 'unevalled))) + +(defun macrop (object) + "Non-nil if and only if OBJECT is a macro." + (let ((def (indirect-function object t))) + (when (consp def) + (or (eq 'macro (car def)) + (and (autoloadp def) (memq (nth 4 def) '(macro t))))))) + +(defun field-at-pos (pos) + "Return the field at position POS, taking stickiness etc into account." + (let ((raw-field (get-char-property (field-beginning pos) 'field))) + (if (eq raw-field 'boundary) + (get-char-property (1- (field-end pos)) 'field) + raw-field))) + +(defun sha1 (object &optional start end binary) + "Return the SHA1 (Secure Hash Algorithm) of an OBJECT. +OBJECT is either a string or a buffer. Optional arguments START and +END are character positions specifying which portion of OBJECT for +computing the hash. If BINARY is non-nil, return a string in binary +form." + (secure-hash 'sha1 object start end binary)) + +(defun function-get (f prop &optional autoload) + "Return the value of property PROP of function F. +If AUTOLOAD is non-nil and F is autoloaded, try to autoload it +in the hope that it will set PROP. If AUTOLOAD is `macro', only do it +if it's an autoloaded macro." + (let ((val nil)) + (while (and (symbolp f) + (null (setq val (get f prop))) + (fboundp f)) + (let ((fundef (symbol-function f))) + (if (and autoload (autoloadp fundef) + (not (equal fundef + (autoload-do-load fundef f + (if (eq autoload 'macro) + 'macro))))) + nil ;Re-try `get' on the same `f'. + (setq f fundef)))) + val)) + +;;;; Support for yanking and text properties. +;; Why here in subr.el rather than in simple.el? --Stef + +(defvar yank-handled-properties) +(defvar yank-excluded-properties) + +(defun remove-yank-excluded-properties (start end) + "Process text properties between START and END, inserted for a `yank'. +Perform the handling specified by `yank-handled-properties', then +remove properties specified by `yank-excluded-properties'." + (let ((inhibit-read-only t)) + (dolist (handler yank-handled-properties) + (let ((prop (car handler)) + (fun (cdr handler)) + (run-start start)) + (while (< run-start end) + (let ((value (get-text-property run-start prop)) + (run-end (next-single-property-change + run-start prop nil end))) + (funcall fun value run-start run-end) + (setq run-start run-end))))) + (if (eq yank-excluded-properties t) + (set-text-properties start end nil) + (remove-list-of-text-properties start end yank-excluded-properties)))) + +(defvar yank-undo-function) + +(defun insert-for-yank (string) + "Call `insert-for-yank-1' repetitively for each `yank-handler' segment. + +See `insert-for-yank-1' for more details." + (let (to) + (while (setq to (next-single-property-change 0 'yank-handler string)) + (insert-for-yank-1 (substring string 0 to)) + (setq string (substring string to)))) + (insert-for-yank-1 string)) + +(defun insert-for-yank-1 (string) + "Insert STRING at point for the `yank' command. +This function is like `insert', except it honors the variables +`yank-handled-properties' and `yank-excluded-properties', and the +`yank-handler' text property. + +Properties listed in `yank-handled-properties' are processed, +then those listed in `yank-excluded-properties' are discarded. + +If STRING has a non-nil `yank-handler' property on its first +character, the normal insert behavior is altered. The value of +the `yank-handler' property must be a list of one to four +elements, of the form (FUNCTION PARAM NOEXCLUDE UNDO). +FUNCTION, if non-nil, should be a function of one argument, an + object to insert; it is called instead of `insert'. +PARAM, if present and non-nil, replaces STRING as the argument to + FUNCTION or `insert'; e.g. if FUNCTION is `yank-rectangle', PARAM + may be a list of strings to insert as a rectangle. +If NOEXCLUDE is present and non-nil, the normal removal of + `yank-excluded-properties' is not performed; instead FUNCTION is + responsible for the removal. This may be necessary if FUNCTION + adjusts point before or after inserting the object. +UNDO, if present and non-nil, should be a function to be called + by `yank-pop' to undo the insertion of the current object. It is + given two arguments, the start and end of the region. FUNCTION + may set `yank-undo-function' to override UNDO." + (let* ((handler (and (stringp string) + (get-text-property 0 'yank-handler string))) + (param (or (nth 1 handler) string)) + (opoint (point)) + (inhibit-read-only inhibit-read-only) + end) + + (setq yank-undo-function t) + (if (nth 0 handler) ; FUNCTION + (funcall (car handler) param) + (insert param)) + (setq end (point)) + + ;; Prevent read-only properties from interfering with the + ;; following text property changes. + (setq inhibit-read-only t) + + (unless (nth 2 handler) ; NOEXCLUDE + (remove-yank-excluded-properties opoint end)) + + ;; If last inserted char has properties, mark them as rear-nonsticky. + (if (and (> end opoint) + (text-properties-at (1- end))) + (put-text-property (1- end) end 'rear-nonsticky t)) + + (if (eq yank-undo-function t) ; not set by FUNCTION + (setq yank-undo-function (nth 3 handler))) ; UNDO + (if (nth 4 handler) ; COMMAND + (setq this-command (nth 4 handler))))) + +(defun insert-buffer-substring-no-properties (buffer &optional start end) + "Insert before point a substring of BUFFER, without text properties. +BUFFER may be a buffer or a buffer name. +Arguments START and END are character positions specifying the substring. +They default to the values of (point-min) and (point-max) in BUFFER." + (let ((opoint (point))) + (insert-buffer-substring buffer start end) + (let ((inhibit-read-only t)) + (set-text-properties opoint (point) nil)))) + +(defun insert-buffer-substring-as-yank (buffer &optional start end) + "Insert before point a part of BUFFER, stripping some text properties. +BUFFER may be a buffer or a buffer name. +Arguments START and END are character positions specifying the substring. +They default to the values of (point-min) and (point-max) in BUFFER. +Before insertion, process text properties according to +`yank-handled-properties' and `yank-excluded-properties'." + ;; Since the buffer text should not normally have yank-handler properties, + ;; there is no need to handle them here. + (let ((opoint (point))) + (insert-buffer-substring buffer start end) + (remove-yank-excluded-properties opoint (point)))) + +(defun yank-handle-font-lock-face-property (face start end) + "If `font-lock-defaults' is nil, apply FACE as a `face' property. +START and END denote the start and end of the text to act on. +Do nothing if FACE is nil." + (and face + (null font-lock-defaults) + (put-text-property start end 'face face))) + +;; This removes `mouse-face' properties in *Help* buffer buttons: +;; http://lists.gnu.org/archive/html/emacs-devel/2002-04/msg00648.html +(defun yank-handle-category-property (category start end) + "Apply property category CATEGORY's properties between START and END." + (when category + (let ((start2 start)) + (while (< start2 end) + (let ((end2 (next-property-change start2 nil end)) + (original (text-properties-at start2))) + (set-text-properties start2 end2 (symbol-plist category)) + (add-text-properties start2 end2 original) + (setq start2 end2)))))) + + +;;;; Synchronous shell commands. + +(defun start-process-shell-command (name buffer &rest args) + "Start a program in a subprocess. Return the process object for it. +NAME is name for process. It is modified if necessary to make it unique. +BUFFER is the buffer (or buffer name) to associate with the process. + Process output goes at end of that buffer, unless you specify + an output stream or filter function to handle the output. + BUFFER may be also nil, meaning that this process is not associated + with any buffer +COMMAND is the shell command to run. + +An old calling convention accepted any number of arguments after COMMAND, +which were just concatenated to COMMAND. This is still supported but strongly +discouraged." + (declare (advertised-calling-convention (name buffer command) "23.1")) + ;; We used to use `exec' to replace the shell with the command, + ;; but that failed to handle (...) and semicolon, etc. + (start-process name buffer shell-file-name shell-command-switch + (mapconcat 'identity args " "))) + +(defun start-file-process-shell-command (name buffer &rest args) + "Start a program in a subprocess. Return the process object for it. +Similar to `start-process-shell-command', but calls `start-file-process'." + (declare (advertised-calling-convention (name buffer command) "23.1")) + (start-file-process + name buffer + (if (file-remote-p default-directory) "/bin/sh" shell-file-name) + (if (file-remote-p default-directory) "-c" shell-command-switch) + (mapconcat 'identity args " "))) + +(defun call-process-shell-command (command &optional infile buffer display + &rest args) + "Execute the shell command COMMAND synchronously in separate process. +The remaining arguments are optional. +The program's input comes from file INFILE (nil means `/dev/null'). +Insert output in BUFFER before point; t means current buffer; + nil for BUFFER means discard it; 0 means discard and don't wait. +BUFFER can also have the form (REAL-BUFFER STDERR-FILE); in that case, +REAL-BUFFER says what to do with standard output, as above, +while STDERR-FILE says what to do with standard error in the child. +STDERR-FILE may be nil (discard standard error output), +t (mix it with ordinary output), or a file name string. + +Fourth arg DISPLAY non-nil means redisplay buffer as output is inserted. +Wildcards and redirection are handled as usual in the shell. + +If BUFFER is 0, `call-process-shell-command' returns immediately with value nil. +Otherwise it waits for COMMAND to terminate and returns a numeric exit +status or a signal description string. +If you quit, the process is killed with SIGINT, or SIGKILL if you quit again. + +An old calling convention accepted any number of arguments after DISPLAY, +which were just concatenated to COMMAND. This is still supported but strongly +discouraged." + (declare (advertised-calling-convention + (command &optional infile buffer display) "24.5")) + ;; We used to use `exec' to replace the shell with the command, + ;; but that failed to handle (...) and semicolon, etc. + (call-process shell-file-name + infile buffer display + shell-command-switch + (mapconcat 'identity (cons command args) " "))) + +(defun process-file-shell-command (command &optional infile buffer display + &rest args) + "Process files synchronously in a separate process. +Similar to `call-process-shell-command', but calls `process-file'." + (declare (advertised-calling-convention + (command &optional infile buffer display) "24.5")) + (process-file + (if (file-remote-p default-directory) "/bin/sh" shell-file-name) + infile buffer display + (if (file-remote-p default-directory) "-c" shell-command-switch) + (mapconcat 'identity (cons command args) " "))) + +;;;; Lisp macros to do various things temporarily. + +(defmacro track-mouse (&rest body) + "Evaluate BODY with mouse movement events enabled. +Within a `track-mouse' form, mouse motion generates input events that + you can read with `read-event'. +Normally, mouse motion is ignored." + (declare (debug t) (indent 0)) + `(internal--track-mouse (lambda () ,@body))) + +(defmacro with-current-buffer (buffer-or-name &rest body) + "Execute the forms in BODY with BUFFER-OR-NAME temporarily current. +BUFFER-OR-NAME must be a buffer or the name of an existing buffer. +The value returned is the value of the last form in BODY. See +also `with-temp-buffer'." + (declare (indent 1) (debug t)) + `(save-current-buffer + (set-buffer ,buffer-or-name) + ,@body)) + +(defun internal--before-with-selected-window (window) + (let ((other-frame (window-frame window))) + (list window (selected-window) + ;; Selecting a window on another frame also changes that + ;; frame's frame-selected-window. We must save&restore it. + (unless (eq (selected-frame) other-frame) + (frame-selected-window other-frame)) + ;; Also remember the top-frame if on ttys. + (unless (eq (selected-frame) other-frame) + (tty-top-frame other-frame))))) + +(defun internal--after-with-selected-window (state) + ;; First reset frame-selected-window. + (when (window-live-p (nth 2 state)) + ;; We don't use set-frame-selected-window because it does not + ;; pass the `norecord' argument to Fselect_window. + (select-window (nth 2 state) 'norecord) + (and (frame-live-p (nth 3 state)) + (not (eq (tty-top-frame) (nth 3 state))) + (select-frame (nth 3 state) 'norecord))) + ;; Then reset the actual selected-window. + (when (window-live-p (nth 1 state)) + (select-window (nth 1 state) 'norecord))) + +(defmacro with-selected-window (window &rest body) + "Execute the forms in BODY with WINDOW as the selected window. +The value returned is the value of the last form in BODY. + +This macro saves and restores the selected window, as well as the +selected window of each frame. It does not change the order of +recently selected windows. If the previously selected window of +some frame is no longer live at the end of BODY, that frame's +selected window is left alone. If the selected window is no +longer live, then whatever window is selected at the end of BODY +remains selected. + +This macro uses `save-current-buffer' to save and restore the +current buffer, since otherwise its normal operation could +potentially make a different buffer current. It does not alter +the buffer list ordering." + (declare (indent 1) (debug t)) + `(let ((save-selected-window--state + (internal--before-with-selected-window ,window))) + (save-current-buffer + (unwind-protect + (progn (select-window (car save-selected-window--state) 'norecord) + ,@body) + (internal--after-with-selected-window save-selected-window--state))))) + +(defmacro with-selected-frame (frame &rest body) + "Execute the forms in BODY with FRAME as the selected frame. +The value returned is the value of the last form in BODY. + +This macro saves and restores the selected frame, and changes the +order of neither the recently selected windows nor the buffers in +the buffer list." + (declare (indent 1) (debug t)) + (let ((old-frame (make-symbol "old-frame")) + (old-buffer (make-symbol "old-buffer"))) + `(let ((,old-frame (selected-frame)) + (,old-buffer (current-buffer))) + (unwind-protect + (progn (select-frame ,frame 'norecord) + ,@body) + (when (frame-live-p ,old-frame) + (select-frame ,old-frame 'norecord)) + (when (buffer-live-p ,old-buffer) + (set-buffer ,old-buffer)))))) + +(defmacro save-window-excursion (&rest body) + "Execute BODY, then restore previous window configuration. +This macro saves the window configuration on the selected frame, +executes BODY, then calls `set-window-configuration' to restore +the saved window configuration. The return value is the last +form in BODY. The window configuration is also restored if BODY +exits nonlocally. + +BEWARE: Most uses of this macro introduce bugs. +E.g. it should not be used to try and prevent some code from opening +a new window, since that window may sometimes appear in another frame, +in which case `save-window-excursion' cannot help." + (declare (indent 0) (debug t)) + (let ((c (make-symbol "wconfig"))) + `(let ((,c (current-window-configuration))) + (unwind-protect (progn ,@body) + (set-window-configuration ,c))))) + +(defun internal-temp-output-buffer-show (buffer) + "Internal function for `with-output-to-temp-buffer'." + (with-current-buffer buffer + (set-buffer-modified-p nil) + (goto-char (point-min))) + + (if temp-buffer-show-function + (funcall temp-buffer-show-function buffer) + (with-current-buffer buffer + (let* ((window + (let ((window-combination-limit + ;; When `window-combination-limit' equals + ;; `temp-buffer' or `temp-buffer-resize' and + ;; `temp-buffer-resize-mode' is enabled in this + ;; buffer bind it to t so resizing steals space + ;; preferably from the window that was split. + (if (or (eq window-combination-limit 'temp-buffer) + (and (eq window-combination-limit + 'temp-buffer-resize) + temp-buffer-resize-mode)) + t + window-combination-limit))) + (display-buffer buffer))) + (frame (and window (window-frame window)))) + (when window + (unless (eq frame (selected-frame)) + (make-frame-visible frame)) + (setq minibuffer-scroll-window window) + (set-window-hscroll window 0) + ;; Don't try this with NOFORCE non-nil! + (set-window-start window (point-min) t) + ;; This should not be necessary. + (set-window-point window (point-min)) + ;; Run `temp-buffer-show-hook', with the chosen window selected. + (with-selected-window window + (run-hooks 'temp-buffer-show-hook)))))) + ;; Return nil. + nil) + +;; Doc is very similar to with-temp-buffer-window. +(defmacro with-output-to-temp-buffer (bufname &rest body) + "Bind `standard-output' to buffer BUFNAME, eval BODY, then show that buffer. + +This construct makes buffer BUFNAME empty before running BODY. +It does not make the buffer current for BODY. +Instead it binds `standard-output' to that buffer, so that output +generated with `prin1' and similar functions in BODY goes into +the buffer. + +At the end of BODY, this marks buffer BUFNAME unmodified and displays +it in a window, but does not select it. The normal way to do this is +by calling `display-buffer', then running `temp-buffer-show-hook'. +However, if `temp-buffer-show-function' is non-nil, it calls that +function instead (and does not run `temp-buffer-show-hook'). The +function gets one argument, the buffer to display. + +The return value of `with-output-to-temp-buffer' is the value of the +last form in BODY. If BODY does not finish normally, the buffer +BUFNAME is not displayed. + +This runs the hook `temp-buffer-setup-hook' before BODY, +with the buffer BUFNAME temporarily current. It runs the hook +`temp-buffer-show-hook' after displaying buffer BUFNAME, with that +buffer temporarily current, and the window that was used to display it +temporarily selected. But it doesn't run `temp-buffer-show-hook' +if it uses `temp-buffer-show-function'. + +By default, the setup hook puts the buffer into Help mode before running BODY. +If BODY does not change the major mode, the show hook makes the buffer +read-only, and scans it for function and variable names to make them into +clickable cross-references. + +See the related form `with-temp-buffer-window'." + (declare (debug t)) + (let ((old-dir (make-symbol "old-dir")) + (buf (make-symbol "buf"))) + `(let* ((,old-dir default-directory) + (,buf + (with-current-buffer (get-buffer-create ,bufname) + (prog1 (current-buffer) + (kill-all-local-variables) + ;; FIXME: delete_all_overlays + (setq default-directory ,old-dir) + (setq buffer-read-only nil) + (setq buffer-file-name nil) + (setq buffer-undo-list t) + (let ((inhibit-read-only t) + (inhibit-modification-hooks t)) + (erase-buffer) + (run-hooks 'temp-buffer-setup-hook))))) + (standard-output ,buf)) + (prog1 (progn ,@body) + (internal-temp-output-buffer-show ,buf))))) + +(defmacro with-temp-file (file &rest body) + "Create a new buffer, evaluate BODY there, and write the buffer to FILE. +The value returned is the value of the last form in BODY. +See also `with-temp-buffer'." + (declare (indent 1) (debug t)) + (let ((temp-file (make-symbol "temp-file")) + (temp-buffer (make-symbol "temp-buffer"))) + `(let ((,temp-file ,file) + (,temp-buffer + (get-buffer-create (generate-new-buffer-name " *temp file*")))) + (unwind-protect + (prog1 + (with-current-buffer ,temp-buffer + ,@body) + (with-current-buffer ,temp-buffer + (write-region nil nil ,temp-file nil 0))) + (and (buffer-name ,temp-buffer) + (kill-buffer ,temp-buffer)))))) + +(defmacro with-temp-message (message &rest body) + "Display MESSAGE temporarily if non-nil while BODY is evaluated. +The original message is restored to the echo area after BODY has finished. +The value returned is the value of the last form in BODY. +MESSAGE is written to the message log buffer if `message-log-max' is non-nil. +If MESSAGE is nil, the echo area and message log buffer are unchanged. +Use a MESSAGE of \"\" to temporarily clear the echo area." + (declare (debug t) (indent 1)) + (let ((current-message (make-symbol "current-message")) + (temp-message (make-symbol "with-temp-message"))) + `(let ((,temp-message ,message) + (,current-message)) + (unwind-protect + (progn + (when ,temp-message + (setq ,current-message (current-message)) + (message "%s" ,temp-message)) + ,@body) + (and ,temp-message + (if ,current-message + (message "%s" ,current-message) + (message nil))))))) + +(defmacro with-temp-buffer (&rest body) + "Create a temporary buffer, and evaluate BODY there like `progn'. +See also `with-temp-file' and `with-output-to-string'." + (declare (indent 0) (debug t)) + (let ((temp-buffer (make-symbol "temp-buffer"))) + `(let ((,temp-buffer (generate-new-buffer " *temp*"))) + ;; FIXME: kill-buffer can change current-buffer in some odd cases. + (with-current-buffer ,temp-buffer + (unwind-protect + (progn ,@body) + (and (buffer-name ,temp-buffer) + (kill-buffer ,temp-buffer))))))) + +(defmacro with-silent-modifications (&rest body) + "Execute BODY, pretending it does not modify the buffer. +If BODY performs real modifications to the buffer's text, other +than cosmetic ones, undo data may become corrupted. + +This macro will run BODY normally, but doesn't count its buffer +modifications as being buffer modifications. This affects things +like `buffer-modified-p', checking whether the file is locked by +someone else, running buffer modification hooks, and other things +of that nature. + +Typically used around modifications of text-properties which do +not really affect the buffer's content." + (declare (debug t) (indent 0)) + (let ((modified (make-symbol "modified"))) + `(let* ((,modified (buffer-modified-p)) + (buffer-undo-list t) + (inhibit-read-only t) + (inhibit-modification-hooks t)) + (unwind-protect + (progn + ,@body) + (unless ,modified + (restore-buffer-modified-p nil)))))) + +(defmacro with-output-to-string (&rest body) + "Execute BODY, return the text it sent to `standard-output', as a string." + (declare (indent 0) (debug t)) + `(let ((standard-output + (get-buffer-create (generate-new-buffer-name " *string-output*")))) + (unwind-protect + (progn + (let ((standard-output standard-output)) + ,@body) + (with-current-buffer standard-output + (buffer-string))) + (kill-buffer standard-output)))) + +(defmacro with-local-quit (&rest body) + "Execute BODY, allowing quits to terminate BODY but not escape further. +When a quit terminates BODY, `with-local-quit' returns nil but +requests another quit. That quit will be processed as soon as quitting +is allowed once again. (Immediately, if `inhibit-quit' is nil.)" + (declare (debug t) (indent 0)) + `(condition-case nil + (let ((inhibit-quit nil)) + ,@body) + (quit (setq quit-flag t) + ;; This call is to give a chance to handle quit-flag + ;; in case inhibit-quit is nil. + ;; Without this, it will not be handled until the next function + ;; call, and that might allow it to exit thru a condition-case + ;; that intends to handle the quit signal next time. + (eval '(ignore nil))))) + +(defmacro while-no-input (&rest body) + "Execute BODY only as long as there's no pending input. +If input arrives, that ends the execution of BODY, +and `while-no-input' returns t. Quitting makes it return nil. +If BODY finishes, `while-no-input' returns whatever value BODY produced." + (declare (debug t) (indent 0)) + (let ((catch-sym (make-symbol "input"))) + `(with-local-quit + (catch ',catch-sym + (let ((throw-on-input ',catch-sym)) + (or (input-pending-p) + (progn ,@body))))))) + +(defmacro condition-case-unless-debug (var bodyform &rest handlers) + "Like `condition-case' except that it does not prevent debugging. +More specifically if `debug-on-error' is set then the debugger will be invoked +even if this catches the signal." + (declare (debug condition-case) (indent 2)) + `(condition-case ,var + ,bodyform + ,@(mapcar (lambda (handler) + `((debug ,@(if (listp (car handler)) (car handler) + (list (car handler)))) + ,@(cdr handler))) + handlers))) + +(define-obsolete-function-alias 'condition-case-no-debug + 'condition-case-unless-debug "24.1") + +(defmacro with-demoted-errors (format &rest body) + "Run BODY and demote any errors to simple messages. +FORMAT is a string passed to `message' to format any error message. +It should contain a single %-sequence; e.g., \"Error: %S\". + +If `debug-on-error' is non-nil, run BODY without catching its errors. +This is to be used around code which is not expected to signal an error +but which should be robust in the unexpected case that an error is signaled. + +For backward compatibility, if FORMAT is not a constant string, it +is assumed to be part of BODY, in which case the message format +used is \"Error: %S\"." + (declare (debug t) (indent 1)) + (let ((err (make-symbol "err")) + (format (if (and (stringp format) body) format + (prog1 "Error: %S" + (if format (push format body)))))) + `(condition-case-unless-debug ,err + ,(macroexp-progn body) + (error (message ,format ,err) nil)))) + +(defmacro combine-after-change-calls (&rest body) + "Execute BODY, but don't call the after-change functions till the end. +If BODY makes changes in the buffer, they are recorded +and the functions on `after-change-functions' are called several times +when BODY is finished. +The return value is the value of the last form in BODY. + +If `before-change-functions' is non-nil, then calls to the after-change +functions can't be deferred, so in that case this macro has no effect. + +Do not alter `after-change-functions' or `before-change-functions' +in BODY." + (declare (indent 0) (debug t)) + `(unwind-protect + (let ((combine-after-change-calls t)) + . ,body) + (combine-after-change-execute))) + +(defmacro with-case-table (table &rest body) + "Execute the forms in BODY with TABLE as the current case table. +The value returned is the value of the last form in BODY." + (declare (indent 1) (debug t)) + (let ((old-case-table (make-symbol "table")) + (old-buffer (make-symbol "buffer"))) + `(let ((,old-case-table (current-case-table)) + (,old-buffer (current-buffer))) + (unwind-protect + (progn (set-case-table ,table) + ,@body) + (with-current-buffer ,old-buffer + (set-case-table ,old-case-table)))))) + +(defmacro with-file-modes (modes &rest body) + "Execute BODY with default file permissions temporarily set to MODES. +MODES is as for `set-default-file-modes'." + (declare (indent 1) (debug t)) + (let ((umask (make-symbol "umask"))) + `(let ((,umask (default-file-modes))) + (unwind-protect + (progn + (set-default-file-modes ,modes) + ,@body) + (set-default-file-modes ,umask))))) + + +;;; Matching and match data. + +(defvar save-match-data-internal) + +;; We use save-match-data-internal as the local variable because +;; that works ok in practice (people should not use that variable elsewhere). +;; We used to use an uninterned symbol; the compiler handles that properly +;; now, but it generates slower code. +(defmacro save-match-data (&rest body) + "Execute the BODY forms, restoring the global value of the match data. +The value returned is the value of the last form in BODY." + ;; It is better not to use backquote here, + ;; because that makes a bootstrapping problem + ;; if you need to recompile all the Lisp files using interpreted code. + (declare (indent 0) (debug t)) + (list 'let + '((save-match-data-internal (match-data))) + (list 'unwind-protect + (cons 'progn body) + ;; It is safe to free (evaporate) markers immediately here, + ;; as Lisp programs should not copy from save-match-data-internal. + '(set-match-data save-match-data-internal 'evaporate)))) + +(defun match-string (num &optional string) + "Return string of text matched by last search. +NUM specifies which parenthesized expression in the last regexp. + Value is nil if NUMth pair didn't match, or there were less than NUM pairs. +Zero means the entire text matched by the whole regexp or whole string. +STRING should be given if the last search was by `string-match' on STRING. +If STRING is nil, the current buffer should be the same buffer +the search/match was performed in." + (if (match-beginning num) + (if string + (substring string (match-beginning num) (match-end num)) + (buffer-substring (match-beginning num) (match-end num))))) + +(defun match-string-no-properties (num &optional string) + "Return string of text matched by last search, without text properties. +NUM specifies which parenthesized expression in the last regexp. + Value is nil if NUMth pair didn't match, or there were less than NUM pairs. +Zero means the entire text matched by the whole regexp or whole string. +STRING should be given if the last search was by `string-match' on STRING. +If STRING is nil, the current buffer should be the same buffer +the search/match was performed in." + (if (match-beginning num) + (if string + (substring-no-properties string (match-beginning num) + (match-end num)) + (buffer-substring-no-properties (match-beginning num) + (match-end num))))) + + +(defun match-substitute-replacement (replacement + &optional fixedcase literal string subexp) + "Return REPLACEMENT as it will be inserted by `replace-match'. +In other words, all back-references in the form `\\&' and `\\N' +are substituted with actual strings matched by the last search. +Optional FIXEDCASE, LITERAL, STRING and SUBEXP have the same +meaning as for `replace-match'." + (let ((match (match-string 0 string))) + (save-match-data + (set-match-data (mapcar (lambda (x) + (if (numberp x) + (- x (match-beginning 0)) + x)) + (match-data t))) + (replace-match replacement fixedcase literal match subexp)))) + + +(defun looking-back (regexp &optional limit greedy) + "Return non-nil if text before point matches regular expression REGEXP. +Like `looking-at' except matches before point, and is slower. +LIMIT if non-nil speeds up the search by specifying a minimum +starting position, to avoid checking matches that would start +before LIMIT. + +If GREEDY is non-nil, extend the match backwards as far as +possible, stopping when a single additional previous character +cannot be part of a match for REGEXP. When the match is +extended, its starting position is allowed to occur before +LIMIT. + +As a general recommendation, try to avoid using `looking-back' +wherever possible, since it is slow." + (let ((start (point)) + (pos + (save-excursion + (and (re-search-backward (concat "\\(?:" regexp "\\)\\=") limit t) + (point))))) + (if (and greedy pos) + (save-restriction + (narrow-to-region (point-min) start) + (while (and (> pos (point-min)) + (save-excursion + (goto-char pos) + (backward-char 1) + (looking-at (concat "\\(?:" regexp "\\)\\'")))) + (setq pos (1- pos))) + (save-excursion + (goto-char pos) + (looking-at (concat "\\(?:" regexp "\\)\\'"))))) + (not (null pos)))) + +(defsubst looking-at-p (regexp) + "\ +Same as `looking-at' except this function does not change the match data." + (let ((inhibit-changing-match-data t)) + (looking-at regexp))) + +(defsubst string-match-p (regexp string &optional start) + "\ +Same as `string-match' except this function does not change the match data." + (let ((inhibit-changing-match-data t)) + (string-match regexp string start))) + +(defun subregexp-context-p (regexp pos &optional start) + "Return non-nil if POS is in a normal subregexp context in REGEXP. +A subregexp context is one where a sub-regexp can appear. +A non-subregexp context is for example within brackets, or within a +repetition bounds operator `\\=\\{...\\}', or right after a `\\'. +If START is non-nil, it should be a position in REGEXP, smaller +than POS, and known to be in a subregexp context." + ;; Here's one possible implementation, with the great benefit that it + ;; reuses the regexp-matcher's own parser, so it understands all the + ;; details of the syntax. A disadvantage is that it needs to match the + ;; error string. + (condition-case err + (progn + (string-match (substring regexp (or start 0) pos) "") + t) + (invalid-regexp + (not (member (cadr err) '("Unmatched [ or [^" + "Unmatched \\{" + "Trailing backslash"))))) + ;; An alternative implementation: + ;; (defconst re-context-re + ;; (let* ((harmless-ch "[^\\[]") + ;; (harmless-esc "\\\\[^{]") + ;; (class-harmless-ch "[^][]") + ;; (class-lb-harmless "[^]:]") + ;; (class-lb-colon-maybe-charclass ":\\([a-z]+:]\\)?") + ;; (class-lb (concat "\\[\\(" class-lb-harmless + ;; "\\|" class-lb-colon-maybe-charclass "\\)")) + ;; (class + ;; (concat "\\[^?]?" + ;; "\\(" class-harmless-ch + ;; "\\|" class-lb "\\)*" + ;; "\\[?]")) ; special handling for bare [ at end of re + ;; (braces "\\\\{[0-9,]+\\\\}")) + ;; (concat "\\`\\(" harmless-ch "\\|" harmless-esc + ;; "\\|" class "\\|" braces "\\)*\\'")) + ;; "Matches any prefix that corresponds to a normal subregexp context.") + ;; (string-match re-context-re (substring regexp (or start 0) pos)) + ) + +;;;; split-string + +(defconst split-string-default-separators "[ \f\t\n\r\v]+" + "The default value of separators for `split-string'. + +A regexp matching strings of whitespace. May be locale-dependent +\(as yet unimplemented). Should not match non-breaking spaces. + +Warning: binding this to a different value and using it as default is +likely to have undesired semantics.") + +;; The specification says that if both SEPARATORS and OMIT-NULLS are +;; defaulted, OMIT-NULLS should be treated as t. Simplifying the logical +;; expression leads to the equivalent implementation that if SEPARATORS +;; is defaulted, OMIT-NULLS is treated as t. +(defun split-string (string &optional separators omit-nulls trim) + "Split STRING into substrings bounded by matches for SEPARATORS. + +The beginning and end of STRING, and each match for SEPARATORS, are +splitting points. The substrings matching SEPARATORS are removed, and +the substrings between the splitting points are collected as a list, +which is returned. + +If SEPARATORS is non-nil, it should be a regular expression matching text +which separates, but is not part of, the substrings. If nil it defaults to +`split-string-default-separators', normally \"[ \\f\\t\\n\\r\\v]+\", and +OMIT-NULLS is forced to t. + +If OMIT-NULLS is t, zero-length substrings are omitted from the list (so +that for the default value of SEPARATORS leading and trailing whitespace +are effectively trimmed). If nil, all zero-length substrings are retained, +which correctly parses CSV format, for example. + +If TRIM is non-nil, it should be a regular expression to match +text to trim from the beginning and end of each substring. If trimming +makes the substring empty, it is treated as null. + +If you want to trim whitespace from the substrings, the reliably correct +way is using TRIM. Making SEPARATORS match that whitespace gives incorrect +results when there is whitespace at the start or end of STRING. If you +see such calls to `split-string', please fix them. + +Note that the effect of `(split-string STRING)' is the same as +`(split-string STRING split-string-default-separators t)'. In the rare +case that you wish to retain zero-length substrings when splitting on +whitespace, use `(split-string STRING split-string-default-separators)'. + +Modifies the match data; use `save-match-data' if necessary." + (let* ((keep-nulls (not (if separators omit-nulls t))) + (rexp (or separators split-string-default-separators)) + (start 0) + this-start this-end + notfirst + (list nil) + (push-one + ;; Push the substring in range THIS-START to THIS-END + ;; onto LIST, trimming it and perhaps discarding it. + (lambda () + (when trim + ;; Discard the trim from start of this substring. + (let ((tem (string-match trim string this-start))) + (and (eq tem this-start) + (setq this-start (match-end 0))))) + + (when (or keep-nulls (< this-start this-end)) + (let ((this (substring string this-start this-end))) + + ;; Discard the trim from end of this substring. + (when trim + (let ((tem (string-match (concat trim "\\'") this 0))) + (and tem (< tem (length this)) + (setq this (substring this 0 tem))))) + + ;; Trimming could make it empty; check again. + (when (or keep-nulls (> (length this) 0)) + (push this list))))))) + + (while (and (string-match rexp string + (if (and notfirst + (= start (match-beginning 0)) + (< start (length string))) + (1+ start) start)) + (< start (length string))) + (setq notfirst t) + (setq this-start start this-end (match-beginning 0) + start (match-end 0)) + + (funcall push-one)) + + ;; Handle the substring at the end of STRING. + (setq this-start start this-end (length string)) + (funcall push-one) + + (nreverse list))) + +(defun combine-and-quote-strings (strings &optional separator) + "Concatenate the STRINGS, adding the SEPARATOR (default \" \"). +This tries to quote the strings to avoid ambiguity such that + (split-string-and-unquote (combine-and-quote-strings strs)) == strs +Only some SEPARATORs will work properly." + (let* ((sep (or separator " ")) + (re (concat "[\\\"]" "\\|" (regexp-quote sep)))) + (mapconcat + (lambda (str) + (if (string-match re str) + (concat "\"" (replace-regexp-in-string "[\\\"]" "\\\\\\&" str) "\"") + str)) + strings sep))) + +(defun split-string-and-unquote (string &optional separator) + "Split the STRING into a list of strings. +It understands Emacs Lisp quoting within STRING, such that + (split-string-and-unquote (combine-and-quote-strings strs)) == strs +The SEPARATOR regexp defaults to \"\\s-+\"." + (let ((sep (or separator "\\s-+")) + (i (string-match "\"" string))) + (if (null i) + (split-string string sep t) ; no quoting: easy + (append (unless (eq i 0) (split-string (substring string 0 i) sep t)) + (let ((rfs (read-from-string string i))) + (cons (car rfs) + (split-string-and-unquote (substring string (cdr rfs)) + sep))))))) + + +;;;; Replacement in strings. + +(defun subst-char-in-string (fromchar tochar string &optional inplace) + "Replace FROMCHAR with TOCHAR in STRING each time it occurs. +Unless optional argument INPLACE is non-nil, return a new string." + (let ((i (length string)) + (newstr (if inplace string (copy-sequence string)))) + (while (> i 0) + (setq i (1- i)) + (if (eq (aref newstr i) fromchar) + (aset newstr i tochar))) + newstr)) + +(defun replace-regexp-in-string (regexp rep string &optional + fixedcase literal subexp start) + "Replace all matches for REGEXP with REP in STRING. + +Return a new string containing the replacements. + +Optional arguments FIXEDCASE, LITERAL and SUBEXP are like the +arguments with the same names of function `replace-match'. If START +is non-nil, start replacements at that index in STRING. + +REP is either a string used as the NEWTEXT arg of `replace-match' or a +function. If it is a function, it is called with the actual text of each +match, and its value is used as the replacement text. When REP is called, +the match data are the result of matching REGEXP against a substring +of STRING. + +To replace only the first match (if any), make REGEXP match up to \\' +and replace a sub-expression, e.g. + (replace-regexp-in-string \"\\\\(foo\\\\).*\\\\'\" \"bar\" \" foo foo\" nil nil 1) + => \" bar foo\"" + + ;; To avoid excessive consing from multiple matches in long strings, + ;; don't just call `replace-match' continually. Walk down the + ;; string looking for matches of REGEXP and building up a (reversed) + ;; list MATCHES. This comprises segments of STRING which weren't + ;; matched interspersed with replacements for segments that were. + ;; [For a `large' number of replacements it's more efficient to + ;; operate in a temporary buffer; we can't tell from the function's + ;; args whether to choose the buffer-based implementation, though it + ;; might be reasonable to do so for long enough STRING.] + (let ((l (length string)) + (start (or start 0)) + matches str mb me) + (save-match-data + (while (and (< start l) (string-match regexp string start)) + (setq mb (match-beginning 0) + me (match-end 0)) + ;; If we matched the empty string, make sure we advance by one char + (when (= me mb) (setq me (min l (1+ mb)))) + ;; Generate a replacement for the matched substring. + ;; Operate only on the substring to minimize string consing. + ;; Set up match data for the substring for replacement; + ;; presumably this is likely to be faster than munging the + ;; match data directly in Lisp. + (string-match regexp (setq str (substring string mb me))) + (setq matches + (cons (replace-match (if (stringp rep) + rep + (funcall rep (match-string 0 str))) + fixedcase literal str subexp) + (cons (substring string start mb) ; unmatched prefix + matches))) + (setq start me)) + ;; Reconstruct a string from the pieces. + (setq matches (cons (substring string start l) matches)) ; leftover + (apply #'concat (nreverse matches))))) + +(defun string-prefix-p (prefix string &optional ignore-case) + "Return non-nil if PREFIX is a prefix of STRING. +If IGNORE-CASE is non-nil, the comparison is done without paying attention +to case differences." + (let ((prefix-length (length prefix))) + (if (> prefix-length (length string)) nil + (eq t (compare-strings prefix 0 prefix-length string + 0 prefix-length ignore-case))))) + +(defun string-suffix-p (suffix string &optional ignore-case) + "Return non-nil if SUFFIX is a suffix of STRING. +If IGNORE-CASE is non-nil, the comparison is done without paying +attention to case differences." + (let ((start-pos (- (length string) (length suffix)))) + (and (>= start-pos 0) + (eq t (compare-strings suffix nil nil + string start-pos nil ignore-case))))) + +(defun bidi-string-mark-left-to-right (str) + "Return a string that can be safely inserted in left-to-right text. + +Normally, inserting a string with right-to-left (RTL) script into +a buffer may cause some subsequent text to be displayed as part +of the RTL segment (usually this affects punctuation characters). +This function returns a string which displays as STR but forces +subsequent text to be displayed as left-to-right. + +If STR contains any RTL character, this function returns a string +consisting of STR followed by an invisible left-to-right mark +\(LRM) character. Otherwise, it returns STR." + (unless (stringp str) + (signal 'wrong-type-argument (list 'stringp str))) + (if (string-match "\\cR" str) + (concat str (propertize (string ?\x200e) 'invisible t)) + str)) + +;;;; Specifying things to do later. + +(defun load-history-regexp (file) + "Form a regexp to find FILE in `load-history'. +FILE, a string, is described in the function `eval-after-load'." + (if (file-name-absolute-p file) + (setq file (file-truename file))) + (concat (if (file-name-absolute-p file) "\\`" "\\(\\`\\|/\\)") + (regexp-quote file) + (if (file-name-extension file) + "" + ;; Note: regexp-opt can't be used here, since we need to call + ;; this before Emacs has been fully started. 2006-05-21 + (concat "\\(" (mapconcat 'regexp-quote load-suffixes "\\|") "\\)?")) + "\\(" (mapconcat 'regexp-quote jka-compr-load-suffixes "\\|") + "\\)?\\'")) + +(defun load-history-filename-element (file-regexp) + "Get the first elt of `load-history' whose car matches FILE-REGEXP. +Return nil if there isn't one." + (let* ((loads load-history) + (load-elt (and loads (car loads)))) + (save-match-data + (while (and loads + (or (null (car load-elt)) + (not (string-match file-regexp (car load-elt))))) + (setq loads (cdr loads) + load-elt (and loads (car loads))))) + load-elt)) + +(put 'eval-after-load 'lisp-indent-function 1) +(defun eval-after-load (file form) + "Arrange that if FILE is loaded, FORM will be run immediately afterwards. +If FILE is already loaded, evaluate FORM right now. +FORM can be an Elisp expression (in which case it's passed to `eval'), +or a function (in which case it's passed to `funcall' with no argument). + +If a matching file is loaded again, FORM will be evaluated again. + +If FILE is a string, it may be either an absolute or a relative file +name, and may have an extension (e.g. \".el\") or may lack one, and +additionally may or may not have an extension denoting a compressed +format (e.g. \".gz\"). + +When FILE is absolute, this first converts it to a true name by chasing +symbolic links. Only a file of this name (see next paragraph regarding +extensions) will trigger the evaluation of FORM. When FILE is relative, +a file whose absolute true name ends in FILE will trigger evaluation. + +When FILE lacks an extension, a file name with any extension will trigger +evaluation. Otherwise, its extension must match FILE's. A further +extension for a compressed format (e.g. \".gz\") on FILE will not affect +this name matching. + +Alternatively, FILE can be a feature (i.e. a symbol), in which case FORM +is evaluated at the end of any file that `provide's this feature. +If the feature is provided when evaluating code not associated with a +file, FORM is evaluated immediately after the provide statement. + +Usually FILE is just a library name like \"font-lock\" or a feature name +like 'font-lock. + +This function makes or adds to an entry on `after-load-alist'." + (declare (compiler-macro + (lambda (whole) + (if (eq 'quote (car-safe form)) + ;; Quote with lambda so the compiler can look inside. + `(eval-after-load ,file (lambda () ,(nth 1 form))) + whole)))) + ;; Add this FORM into after-load-alist (regardless of whether we'll be + ;; evaluating it now). + (let* ((regexp-or-feature + (if (stringp file) + (setq file (purecopy (load-history-regexp file))) + file)) + (elt (assoc regexp-or-feature after-load-alist)) + (func + (if (functionp form) form + ;; Try to use the "current" lexical/dynamic mode for `form'. + (eval `(lambda () ,form) lexical-binding)))) + (unless elt + (setq elt (list regexp-or-feature)) + (push elt after-load-alist)) + ;; Is there an already loaded file whose name (or `provide' name) + ;; matches FILE? + (prog1 (if (if (stringp file) + (load-history-filename-element regexp-or-feature) + (featurep file)) + (funcall func)) + (let ((delayed-func + (if (not (symbolp regexp-or-feature)) func + ;; For features, the after-load-alist elements get run when + ;; `provide' is called rather than at the end of the file. + ;; So add an indirection to make sure that `func' is really run + ;; "after-load" in case the provide call happens early. + (lambda () + (if (not load-file-name) + ;; Not being provided from a file, run func right now. + (funcall func) + (let ((lfn load-file-name) + ;; Don't use letrec, because equal (in + ;; add/remove-hook) would get trapped in a cycle. + (fun (make-symbol "eval-after-load-helper"))) + (fset fun (lambda (file) + (when (equal file lfn) + (remove-hook 'after-load-functions fun) + (funcall func)))) + (add-hook 'after-load-functions fun 'append))))))) + ;; Add FORM to the element unless it's already there. + (unless (member delayed-func (cdr elt)) + (nconc elt (list delayed-func))))))) + +(defmacro with-eval-after-load (file &rest body) + "Execute BODY after FILE is loaded. +FILE is normally a feature name, but it can also be a file name, +in case that file does not provide any feature." + (declare (indent 1) (debug t)) + `(eval-after-load ,file (lambda () ,@body))) + +(defvar after-load-functions nil + "Special hook run after loading a file. +Each function there is called with a single argument, the absolute +name of the file just loaded.") + +(defun do-after-load-evaluation (abs-file) + "Evaluate all `eval-after-load' forms, if any, for ABS-FILE. +ABS-FILE, a string, should be the absolute true name of a file just loaded. +This function is called directly from the C code." + ;; Run the relevant eval-after-load forms. + (dolist (a-l-element after-load-alist) + (when (and (stringp (car a-l-element)) + (string-match-p (car a-l-element) abs-file)) + ;; discard the file name regexp + (mapc #'funcall (cdr a-l-element)))) + ;; Complain when the user uses obsolete files. + (when (save-match-data + (and (string-match "/obsolete/\\([^/]*\\)\\'" abs-file) + (not (equal "loaddefs.el" (match-string 1 abs-file))))) + ;; Maybe we should just use display-warning? This seems yucky... + (let* ((file (file-name-nondirectory abs-file)) + (msg (format "Package %s is obsolete!" + (substring file 0 + (string-match "\\.elc?\\>" file))))) + ;; Cribbed from cl--compiling-file. + (if (and (boundp 'byte-compile--outbuffer) + (bufferp (symbol-value 'byte-compile--outbuffer)) + (equal (buffer-name (symbol-value 'byte-compile--outbuffer)) + " *Compiler Output*")) + ;; Don't warn about obsolete files using other obsolete files. + (unless (and (stringp byte-compile-current-file) + (string-match-p "/obsolete/[^/]*\\'" + (expand-file-name + byte-compile-current-file + byte-compile-root-dir))) + (byte-compile-log-warning msg)) + (run-with-timer 0 nil + (lambda (msg) + (message "%s" msg)) + msg)))) + + ;; Finally, run any other hook. + (run-hook-with-args 'after-load-functions abs-file)) + +(defun eval-next-after-load (file) + "Read the following input sexp, and run it whenever FILE is loaded. +This makes or adds to an entry on `after-load-alist'. +FILE should be the name of a library, with no directory name." + (declare (obsolete eval-after-load "23.2")) + (eval-after-load file (read))) + + +(defun display-delayed-warnings () + "Display delayed warnings from `delayed-warnings-list'. +Used from `delayed-warnings-hook' (which see)." + (dolist (warning (nreverse delayed-warnings-list)) + (apply 'display-warning warning)) + (setq delayed-warnings-list nil)) + +(defun collapse-delayed-warnings () + "Remove duplicates from `delayed-warnings-list'. +Collapse identical adjacent warnings into one (plus count). +Used from `delayed-warnings-hook' (which see)." + (let ((count 1) + collapsed warning) + (while delayed-warnings-list + (setq warning (pop delayed-warnings-list)) + (if (equal warning (car delayed-warnings-list)) + (setq count (1+ count)) + (when (> count 1) + (setcdr warning (cons (format "%s [%d times]" (cadr warning) count) + (cddr warning))) + (setq count 1)) + (push warning collapsed))) + (setq delayed-warnings-list (nreverse collapsed)))) + +;; At present this is only used for Emacs internals. +;; Ref http://lists.gnu.org/archive/html/emacs-devel/2012-02/msg00085.html +(defvar delayed-warnings-hook '(collapse-delayed-warnings + display-delayed-warnings) + "Normal hook run to process and display delayed warnings. +By default, this hook contains functions to consolidate the +warnings listed in `delayed-warnings-list', display them, and set +`delayed-warnings-list' back to nil.") + +(defun delay-warning (type message &optional level buffer-name) + "Display a delayed warning. +Aside from going through `delayed-warnings-list', this is equivalent +to `display-warning'." + (push (list type message level buffer-name) delayed-warnings-list)) + + +;;;; invisibility specs + +(defun add-to-invisibility-spec (element) + "Add ELEMENT to `buffer-invisibility-spec'. +See documentation for `buffer-invisibility-spec' for the kind of elements +that can be added." + (if (eq buffer-invisibility-spec t) + (setq buffer-invisibility-spec (list t))) + (setq buffer-invisibility-spec + (cons element buffer-invisibility-spec))) + +(defun remove-from-invisibility-spec (element) + "Remove ELEMENT from `buffer-invisibility-spec'." + (if (consp buffer-invisibility-spec) + (setq buffer-invisibility-spec + (delete element buffer-invisibility-spec)))) + +;;;; Syntax tables. + +(defmacro with-syntax-table (table &rest body) + "Evaluate BODY with syntax table of current buffer set to TABLE. +The syntax table of the current buffer is saved, BODY is evaluated, and the +saved table is restored, even in case of an abnormal exit. +Value is what BODY returns." + (declare (debug t) (indent 1)) + (let ((old-table (make-symbol "table")) + (old-buffer (make-symbol "buffer"))) + `(let ((,old-table (syntax-table)) + (,old-buffer (current-buffer))) + (unwind-protect + (progn + (set-syntax-table ,table) + ,@body) + (save-current-buffer + (set-buffer ,old-buffer) + (set-syntax-table ,old-table)))))) + +(defun make-syntax-table (&optional oldtable) + "Return a new syntax table. +Create a syntax table which inherits from OLDTABLE (if non-nil) or +from `standard-syntax-table' otherwise." + (let ((table (make-char-table 'syntax-table nil))) + (set-char-table-parent table (or oldtable (standard-syntax-table))) + table)) + +(defun syntax-after (pos) + "Return the raw syntax descriptor for the char after POS. +If POS is outside the buffer's accessible portion, return nil." + (unless (or (< pos (point-min)) (>= pos (point-max))) + (let ((st (if parse-sexp-lookup-properties + (get-char-property pos 'syntax-table)))) + (if (consp st) st + (aref (or st (syntax-table)) (char-after pos)))))) + +(defun syntax-class (syntax) + "Return the code for the syntax class described by SYNTAX. + +SYNTAX should be a raw syntax descriptor; the return value is a +integer which encodes the corresponding syntax class. See Info +node `(elisp)Syntax Table Internals' for a list of codes. + +If SYNTAX is nil, return nil." + (and syntax (logand (car syntax) 65535))) + +;; Utility motion commands + +;; Whitespace + +(defun forward-whitespace (arg) + "Move point to the end of the next sequence of whitespace chars. +Each such sequence may be a single newline, or a sequence of +consecutive space and/or tab characters. +With prefix argument ARG, do it ARG times if positive, or move +backwards ARG times if negative." + (interactive "^p") + (if (natnump arg) + (re-search-forward "[ \t]+\\|\n" nil 'move arg) + (while (< arg 0) + (if (re-search-backward "[ \t]+\\|\n" nil 'move) + (or (eq (char-after (match-beginning 0)) ?\n) + (skip-chars-backward " \t"))) + (setq arg (1+ arg))))) + +;; Symbols + +(defun forward-symbol (arg) + "Move point to the next position that is the end of a symbol. +A symbol is any sequence of characters that are in either the +word constituent or symbol constituent syntax class. +With prefix argument ARG, do it ARG times if positive, or move +backwards ARG times if negative." + (interactive "^p") + (if (natnump arg) + (re-search-forward "\\(\\sw\\|\\s_\\)+" nil 'move arg) + (while (< arg 0) + (if (re-search-backward "\\(\\sw\\|\\s_\\)+" nil 'move) + (skip-syntax-backward "w_")) + (setq arg (1+ arg))))) + +;; Syntax blocks + +(defun forward-same-syntax (&optional arg) + "Move point past all characters with the same syntax class. +With prefix argument ARG, do it ARG times if positive, or move +backwards ARG times if negative." + (interactive "^p") + (or arg (setq arg 1)) + (while (< arg 0) + (skip-syntax-backward + (char-to-string (char-syntax (char-before)))) + (setq arg (1+ arg))) + (while (> arg 0) + (skip-syntax-forward (char-to-string (char-syntax (char-after)))) + (setq arg (1- arg)))) + + +;;;; Text clones + +(defvar text-clone--maintaining nil) + +(defun text-clone--maintain (ol1 after beg end &optional _len) + "Propagate the changes made under the overlay OL1 to the other clones. +This is used on the `modification-hooks' property of text clones." + (when (and after (not undo-in-progress) + (not text-clone--maintaining) + (overlay-start ol1)) + (let ((margin (if (overlay-get ol1 'text-clone-spreadp) 1 0))) + (setq beg (max beg (+ (overlay-start ol1) margin))) + (setq end (min end (- (overlay-end ol1) margin))) + (when (<= beg end) + (save-excursion + (when (overlay-get ol1 'text-clone-syntax) + ;; Check content of the clone's text. + (let ((cbeg (+ (overlay-start ol1) margin)) + (cend (- (overlay-end ol1) margin))) + (goto-char cbeg) + (save-match-data + (if (not (re-search-forward + (overlay-get ol1 'text-clone-syntax) cend t)) + ;; Mark the overlay for deletion. + (setq end cbeg) + (when (< (match-end 0) cend) + ;; Shrink the clone at its end. + (setq end (min end (match-end 0))) + (move-overlay ol1 (overlay-start ol1) + (+ (match-end 0) margin))) + (when (> (match-beginning 0) cbeg) + ;; Shrink the clone at its beginning. + (setq beg (max (match-beginning 0) beg)) + (move-overlay ol1 (- (match-beginning 0) margin) + (overlay-end ol1))))))) + ;; Now go ahead and update the clones. + (let ((head (- beg (overlay-start ol1))) + (tail (- (overlay-end ol1) end)) + (str (buffer-substring beg end)) + (nothing-left t) + (text-clone--maintaining t)) + (dolist (ol2 (overlay-get ol1 'text-clones)) + (let ((oe (overlay-end ol2))) + (unless (or (eq ol1 ol2) (null oe)) + (setq nothing-left nil) + (let ((mod-beg (+ (overlay-start ol2) head))) + ;;(overlay-put ol2 'modification-hooks nil) + (goto-char (- (overlay-end ol2) tail)) + (unless (> mod-beg (point)) + (save-excursion (insert str)) + (delete-region mod-beg (point))) + ;;(overlay-put ol2 'modification-hooks '(text-clone--maintain)) + )))) + (if nothing-left (delete-overlay ol1)))))))) + +(defun text-clone-create (start end &optional spreadp syntax) + "Create a text clone of START...END at point. +Text clones are chunks of text that are automatically kept identical: +changes done to one of the clones will be immediately propagated to the other. + +The buffer's content at point is assumed to be already identical to +the one between START and END. +If SYNTAX is provided it's a regexp that describes the possible text of +the clones; the clone will be shrunk or killed if necessary to ensure that +its text matches the regexp. +If SPREADP is non-nil it indicates that text inserted before/after the +clone should be incorporated in the clone." + ;; To deal with SPREADP we can either use an overlay with `nil t' along + ;; with insert-(behind|in-front-of)-hooks or use a slightly larger overlay + ;; (with a one-char margin at each end) with `t nil'. + ;; We opted for a larger overlay because it behaves better in the case + ;; where the clone is reduced to the empty string (we want the overlay to + ;; stay when the clone's content is the empty string and we want to use + ;; `evaporate' to make sure those overlays get deleted when needed). + ;; + (let* ((pt-end (+ (point) (- end start))) + (start-margin (if (or (not spreadp) (bobp) (<= start (point-min))) + 0 1)) + (end-margin (if (or (not spreadp) + (>= pt-end (point-max)) + (>= start (point-max))) + 0 1)) + ;; FIXME: Reuse overlays at point to extend dups! + (ol1 (make-overlay (- start start-margin) (+ end end-margin) nil t)) + (ol2 (make-overlay (- (point) start-margin) (+ pt-end end-margin) nil t)) + (dups (list ol1 ol2))) + (overlay-put ol1 'modification-hooks '(text-clone--maintain)) + (when spreadp (overlay-put ol1 'text-clone-spreadp t)) + (when syntax (overlay-put ol1 'text-clone-syntax syntax)) + ;;(overlay-put ol1 'face 'underline) + (overlay-put ol1 'evaporate t) + (overlay-put ol1 'text-clones dups) + ;; + (overlay-put ol2 'modification-hooks '(text-clone--maintain)) + (when spreadp (overlay-put ol2 'text-clone-spreadp t)) + (when syntax (overlay-put ol2 'text-clone-syntax syntax)) + ;;(overlay-put ol2 'face 'underline) + (overlay-put ol2 'evaporate t) + (overlay-put ol2 'text-clones dups))) + +;;;; Mail user agents. + +;; Here we include just enough for other packages to be able +;; to define them. + +(defun define-mail-user-agent (symbol composefunc sendfunc + &optional abortfunc hookvar) + "Define a symbol to identify a mail-sending package for `mail-user-agent'. + +SYMBOL can be any Lisp symbol. Its function definition and/or +value as a variable do not matter for this usage; we use only certain +properties on its property list, to encode the rest of the arguments. + +COMPOSEFUNC is program callable function that composes an outgoing +mail message buffer. This function should set up the basics of the +buffer without requiring user interaction. It should populate the +standard mail headers, leaving the `to:' and `subject:' headers blank +by default. + +COMPOSEFUNC should accept several optional arguments--the same +arguments that `compose-mail' takes. See that function's documentation. + +SENDFUNC is the command a user would run to send the message. + +Optional ABORTFUNC is the command a user would run to abort the +message. For mail packages that don't have a separate abort function, +this can be `kill-buffer' (the equivalent of omitting this argument). + +Optional HOOKVAR is a hook variable that gets run before the message +is actually sent. Callers that use the `mail-user-agent' may +install a hook function temporarily on this hook variable. +If HOOKVAR is nil, `mail-send-hook' is used. + +The properties used on SYMBOL are `composefunc', `sendfunc', +`abortfunc', and `hookvar'." + (put symbol 'composefunc composefunc) + (put symbol 'sendfunc sendfunc) + (put symbol 'abortfunc (or abortfunc 'kill-buffer)) + (put symbol 'hookvar (or hookvar 'mail-send-hook))) + +(defvar called-interactively-p-functions nil + "Special hook called to skip special frames in `called-interactively-p'. +The functions are called with 3 arguments: (I FRAME1 FRAME2), +where FRAME1 is a \"current frame\", FRAME2 is the next frame, +I is the index of the frame after FRAME2. It should return nil +if those frames don't seem special and otherwise, it should return +the number of frames to skip (minus 1).") + +(defconst internal--funcall-interactively + (symbol-function 'funcall-interactively)) + +(defun called-interactively-p (&optional kind) + "Return t if the containing function was called by `call-interactively'. +If KIND is `interactive', then only return t if the call was made +interactively by the user, i.e. not in `noninteractive' mode nor +when `executing-kbd-macro'. +If KIND is `any', on the other hand, it will return t for any kind of +interactive call, including being called as the binding of a key or +from a keyboard macro, even in `noninteractive' mode. + +This function is very brittle, it may fail to return the intended result when +the code is debugged, advised, or instrumented in some form. Some macros and +special forms (such as `condition-case') may also sometimes wrap their bodies +in a `lambda', so any call to `called-interactively-p' from those bodies will +indicate whether that lambda (rather than the surrounding function) was called +interactively. + +Instead of using this function, it is cleaner and more reliable to give your +function an extra optional argument whose `interactive' spec specifies +non-nil unconditionally (\"p\" is a good way to do this), or via +\(not (or executing-kbd-macro noninteractive)). + +The only known proper use of `interactive' for KIND is in deciding +whether to display a helpful message, or how to display it. If you're +thinking of using it for any other purpose, it is quite likely that +you're making a mistake. Think: what do you want to do when the +command is called from a keyboard macro?" + (declare (advertised-calling-convention (kind) "23.1")) + (when (not (and (eq kind 'interactive) + (or executing-kbd-macro noninteractive))) + (let* ((i 1) ;; 0 is the called-interactively-p frame. + frame nextframe + (get-next-frame + (lambda () + (setq frame nextframe) + (setq nextframe (backtrace-frame i 'called-interactively-p)) + ;; (message "Frame %d = %S" i nextframe) + (setq i (1+ i))))) + (funcall get-next-frame) ;; Get the first frame. + (while + ;; FIXME: The edebug and advice handling should be made modular and + ;; provided directly by edebug.el and nadvice.el. + (progn + ;; frame =(backtrace-frame i-2) + ;; nextframe=(backtrace-frame i-1) + (funcall get-next-frame) + ;; `pcase' would be a fairly good fit here, but it sometimes moves + ;; branches within local functions, which then messes up the + ;; `backtrace-frame' data we get, + (or + ;; Skip special forms (from non-compiled code). + (and frame (null (car frame))) + ;; Skip also `interactive-p' (because we don't want to know if + ;; interactive-p was called interactively but if it's caller was) + ;; and `byte-code' (idem; this appears in subexpressions of things + ;; like condition-case, which are wrapped in a separate bytecode + ;; chunk). + ;; FIXME: For lexical-binding code, this is much worse, + ;; because the frames look like "byte-code -> funcall -> #[...]", + ;; which is not a reliable signature. + (memq (nth 1 frame) '(interactive-p 'byte-code)) + ;; Skip package-specific stack-frames. + (let ((skip (run-hook-with-args-until-success + 'called-interactively-p-functions + i frame nextframe))) + (pcase skip + (`nil nil) + (`0 t) + (_ (setq i (+ i skip -1)) (funcall get-next-frame))))))) + ;; Now `frame' should be "the function from which we were called". + (pcase (cons frame nextframe) + ;; No subr calls `interactive-p', so we can rule that out. + (`((,_ ,(pred (lambda (f) (subrp (indirect-function f)))) . ,_) . ,_) nil) + ;; In case #<subr funcall-interactively> without going through the + ;; `funcall-interactively' symbol (bug#3984). + (`(,_ . (t ,(pred (lambda (f) + (eq internal--funcall-interactively + (indirect-function f)))) + . ,_)) + t))))) + +(defun interactive-p () + "Return t if the containing function was run directly by user input. +This means that the function was called with `call-interactively' +\(which includes being called as the binding of a key) +and input is currently coming from the keyboard (not a keyboard macro), +and Emacs is not running in batch mode (`noninteractive' is nil). + +The only known proper use of `interactive-p' is in deciding whether to +display a helpful message, or how to display it. If you're thinking +of using it for any other purpose, it is quite likely that you're +making a mistake. Think: what do you want to do when the command is +called from a keyboard macro or in batch mode? + +To test whether your function was called with `call-interactively', +either (i) add an extra optional argument and give it an `interactive' +spec that specifies non-nil unconditionally (such as \"p\"); or (ii) +use `called-interactively-p'." + (declare (obsolete called-interactively-p "23.2")) + (called-interactively-p 'interactive)) + +(defun internal-push-keymap (keymap symbol) + (let ((map (symbol-value symbol))) + (unless (memq keymap map) + (unless (memq 'add-keymap-witness (symbol-value symbol)) + (setq map (make-composed-keymap nil (symbol-value symbol))) + (push 'add-keymap-witness (cdr map)) + (set symbol map)) + (push keymap (cdr map))))) + +(defun internal-pop-keymap (keymap symbol) + (let ((map (symbol-value symbol))) + (when (memq keymap map) + (setf (cdr map) (delq keymap (cdr map)))) + (let ((tail (cddr map))) + (and (or (null tail) (keymapp tail)) + (eq 'add-keymap-witness (nth 1 map)) + (set symbol tail))))) + +(define-obsolete-function-alias + 'set-temporary-overlay-map 'set-transient-map "24.4") + +(defun set-transient-map (map &optional keep-pred on-exit) + "Set MAP as a temporary keymap taking precedence over other keymaps. +Normally, MAP is used only once, to look up the very next key. +However, if the optional argument KEEP-PRED is t, MAP stays +active if a key from MAP is used. KEEP-PRED can also be a +function of no arguments: it is called from `pre-command-hook' and +if it returns non-nil, then MAP stays active. + +Optional arg ON-EXIT, if non-nil, specifies a function that is +called, with no arguments, after MAP is deactivated. + +This uses `overriding-terminal-local-map' which takes precedence over all other +keymaps. As usual, if no match for a key is found in MAP, the normal key +lookup sequence then continues. + +This returns an \"exit function\", which can be called with no argument +to deactivate this transient map, regardless of KEEP-PRED." + (let* ((clearfun (make-symbol "clear-transient-map")) + (exitfun + (lambda () + (internal-pop-keymap map 'overriding-terminal-local-map) + (remove-hook 'pre-command-hook clearfun) + (when on-exit (funcall on-exit))))) + ;; Don't use letrec, because equal (in add/remove-hook) would get trapped + ;; in a cycle. + (fset clearfun + (lambda () + (with-demoted-errors "set-transient-map PCH: %S" + (unless (cond + ((null keep-pred) nil) + ((not (eq map (cadr overriding-terminal-local-map))) + ;; There's presumably some other transient-map in + ;; effect. Wait for that one to terminate before we + ;; remove ourselves. + ;; For example, if isearch and C-u both use transient + ;; maps, then the lifetime of the C-u should be nested + ;; within isearch's, so the pre-command-hook of + ;; isearch should be suspended during the C-u one so + ;; we don't exit isearch just because we hit 1 after + ;; C-u and that 1 exits isearch whereas it doesn't + ;; exit C-u. + t) + ((eq t keep-pred) + (eq this-command + (lookup-key map (this-command-keys-vector)))) + (t (funcall keep-pred))) + (funcall exitfun))))) + (add-hook 'pre-command-hook clearfun) + (internal-push-keymap map 'overriding-terminal-local-map) + exitfun)) + +;;;; Progress reporters. + +;; Progress reporter has the following structure: +;; +;; (NEXT-UPDATE-VALUE . [NEXT-UPDATE-TIME +;; MIN-VALUE +;; MAX-VALUE +;; MESSAGE +;; MIN-CHANGE +;; MIN-TIME]) +;; +;; This weirdness is for optimization reasons: we want +;; `progress-reporter-update' to be as fast as possible, so +;; `(car reporter)' is better than `(aref reporter 0)'. +;; +;; NEXT-UPDATE-TIME is a float. While `float-time' loses a couple +;; digits of precision, it doesn't really matter here. On the other +;; hand, it greatly simplifies the code. + +(defsubst progress-reporter-update (reporter &optional value) + "Report progress of an operation in the echo area. +REPORTER should be the result of a call to `make-progress-reporter'. + +If REPORTER is a numerical progress reporter---i.e. if it was + made using non-nil MIN-VALUE and MAX-VALUE arguments to + `make-progress-reporter'---then VALUE should be a number between + MIN-VALUE and MAX-VALUE. + +If REPORTER is a non-numerical reporter, VALUE should be nil. + +This function is relatively inexpensive. If the change since +last update is too small or insufficient time has passed, it does +nothing." + (when (or (not (numberp value)) ; For pulsing reporter + (>= value (car reporter))) ; For numerical reporter + (progress-reporter-do-update reporter value))) + +(defun make-progress-reporter (message &optional min-value max-value + current-value min-change min-time) + "Return progress reporter object for use with `progress-reporter-update'. + +MESSAGE is shown in the echo area, with a status indicator +appended to the end. When you call `progress-reporter-done', the +word \"done\" is printed after the MESSAGE. You can change the +MESSAGE of an existing progress reporter by calling +`progress-reporter-force-update'. + +MIN-VALUE and MAX-VALUE, if non-nil, are starting (0% complete) +and final (100% complete) states of operation; the latter should +be larger. In this case, the status message shows the percentage +progress. + +If MIN-VALUE and/or MAX-VALUE is omitted or nil, the status +message shows a \"spinning\", non-numeric indicator. + +Optional CURRENT-VALUE is the initial progress; the default is +MIN-VALUE. +Optional MIN-CHANGE is the minimal change in percents to report; +the default is 1%. +CURRENT-VALUE and MIN-CHANGE do not have any effect if MIN-VALUE +and/or MAX-VALUE are nil. + +Optional MIN-TIME specifies the minimum interval time between +echo area updates (default is 0.2 seconds.) If the function +`float-time' is not present, time is not tracked at all. If the +OS is not capable of measuring fractions of seconds, this +parameter is effectively rounded up." + (when (string-match "[[:alnum:]]\\'" message) + (setq message (concat message "..."))) + (unless min-time + (setq min-time 0.2)) + (let ((reporter + ;; Force a call to `message' now + (cons (or min-value 0) + (vector (if (and (fboundp 'float-time) + (>= min-time 0.02)) + (float-time) nil) + min-value + max-value + message + (if min-change (max (min min-change 50) 1) 1) + min-time)))) + (progress-reporter-update reporter (or current-value min-value)) + reporter)) + +(defun progress-reporter-force-update (reporter &optional value new-message) + "Report progress of an operation in the echo area unconditionally. + +The first two arguments are the same as in `progress-reporter-update'. +NEW-MESSAGE, if non-nil, sets a new message for the reporter." + (let ((parameters (cdr reporter))) + (when new-message + (aset parameters 3 new-message)) + (when (aref parameters 0) + (aset parameters 0 (float-time))) + (progress-reporter-do-update reporter value))) + +(defvar progress-reporter--pulse-characters ["-" "\\" "|" "/"] + "Characters to use for pulsing progress reporters.") + +(defun progress-reporter-do-update (reporter value) + (let* ((parameters (cdr reporter)) + (update-time (aref parameters 0)) + (min-value (aref parameters 1)) + (max-value (aref parameters 2)) + (text (aref parameters 3)) + (enough-time-passed + ;; See if enough time has passed since the last update. + (or (not update-time) + (when (>= (float-time) update-time) + ;; Calculate time for the next update + (aset parameters 0 (+ update-time (aref parameters 5))))))) + (cond ((and min-value max-value) + ;; Numerical indicator + (let* ((one-percent (/ (- max-value min-value) 100.0)) + (percentage (if (= max-value min-value) + 0 + (truncate (/ (- value min-value) + one-percent))))) + ;; Calculate NEXT-UPDATE-VALUE. If we are not printing + ;; message because not enough time has passed, use 1 + ;; instead of MIN-CHANGE. This makes delays between echo + ;; area updates closer to MIN-TIME. + (setcar reporter + (min (+ min-value (* (+ percentage + (if enough-time-passed + ;; MIN-CHANGE + (aref parameters 4) + 1)) + one-percent)) + max-value)) + (when (integerp value) + (setcar reporter (ceiling (car reporter)))) + ;; Only print message if enough time has passed + (when enough-time-passed + (if (> percentage 0) + (message "%s%d%%" text percentage) + (message "%s" text))))) + ;; Pulsing indicator + (enough-time-passed + (let ((index (mod (1+ (car reporter)) 4)) + (message-log-max nil)) + (setcar reporter index) + (message "%s %s" + text + (aref progress-reporter--pulse-characters + index))))))) + +(defun progress-reporter-done (reporter) + "Print reporter's message followed by word \"done\" in echo area." + (message "%sdone" (aref (cdr reporter) 3))) + +(defmacro dotimes-with-progress-reporter (spec message &rest body) + "Loop a certain number of times and report progress in the echo area. +Evaluate BODY with VAR bound to successive integers running from +0, inclusive, to COUNT, exclusive. Then evaluate RESULT to get +the return value (nil if RESULT is omitted). + +At each iteration MESSAGE followed by progress percentage is +printed in the echo area. After the loop is finished, MESSAGE +followed by word \"done\" is printed. This macro is a +convenience wrapper around `make-progress-reporter' and friends. + +\(fn (VAR COUNT [RESULT]) MESSAGE BODY...)" + (declare (indent 2) (debug ((symbolp form &optional form) form body))) + (let ((temp (make-symbol "--dotimes-temp--")) + (temp2 (make-symbol "--dotimes-temp2--")) + (start 0) + (end (nth 1 spec))) + `(let ((,temp ,end) + (,(car spec) ,start) + (,temp2 (make-progress-reporter ,message ,start ,end))) + (while (< ,(car spec) ,temp) + ,@body + (progress-reporter-update ,temp2 + (setq ,(car spec) (1+ ,(car spec))))) + (progress-reporter-done ,temp2) + nil ,@(cdr (cdr spec))))) + + +;;;; Comparing version strings. + +(defconst version-separator "." + "Specify the string used to separate the version elements. + +Usually the separator is \".\", but it can be any other string.") + + +(defconst version-regexp-alist + '(("^[-_+ ]?snapshot$" . -4) + ;; treat "1.2.3-20050920" and "1.2-3" as snapshot releases + ("^[-_+]$" . -4) + ;; treat "1.2.3-CVS" as snapshot release + ("^[-_+ ]?\\(cvs\\|git\\|bzr\\|svn\\|hg\\|darcs\\)$" . -4) + ("^[-_+ ]?alpha$" . -3) + ("^[-_+ ]?beta$" . -2) + ("^[-_+ ]?\\(pre\\|rc\\)$" . -1)) + "Specify association between non-numeric version and its priority. + +This association is used to handle version string like \"1.0pre2\", +\"0.9alpha1\", etc. It's used by `version-to-list' (which see) to convert the +non-numeric part of a version string to an integer. For example: + + String Version Integer List Version + \"0.9snapshot\" (0 9 -4) + \"1.0-git\" (1 0 -4) + \"1.0pre2\" (1 0 -1 2) + \"1.0PRE2\" (1 0 -1 2) + \"22.8beta3\" (22 8 -2 3) + \"22.8 Beta3\" (22 8 -2 3) + \"0.9alpha1\" (0 9 -3 1) + \"0.9AlphA1\" (0 9 -3 1) + \"0.9 alpha\" (0 9 -3) + +Each element has the following form: + + (REGEXP . PRIORITY) + +Where: + +REGEXP regexp used to match non-numeric part of a version string. + It should begin with the `^' anchor and end with a `$' to + prevent false hits. Letter-case is ignored while matching + REGEXP. + +PRIORITY a negative integer specifying non-numeric priority of REGEXP.") + + +(defun version-to-list (ver) + "Convert version string VER into a list of integers. + +The version syntax is given by the following EBNF: + + VERSION ::= NUMBER ( SEPARATOR NUMBER )*. + + NUMBER ::= (0|1|2|3|4|5|6|7|8|9)+. + + SEPARATOR ::= `version-separator' (which see) + | `version-regexp-alist' (which see). + +The NUMBER part is optional if SEPARATOR is a match for an element +in `version-regexp-alist'. + +Examples of valid version syntax: + + 1.0pre2 1.0.7.5 22.8beta3 0.9alpha1 6.9.30Beta + +Examples of invalid version syntax: + + 1.0prepre2 1.0..7.5 22.8X3 alpha3.2 .5 + +Examples of version conversion: + + Version String Version as a List of Integers + \"1.0.7.5\" (1 0 7 5) + \"1.0pre2\" (1 0 -1 2) + \"1.0PRE2\" (1 0 -1 2) + \"22.8beta3\" (22 8 -2 3) + \"22.8Beta3\" (22 8 -2 3) + \"0.9alpha1\" (0 9 -3 1) + \"0.9AlphA1\" (0 9 -3 1) + \"0.9alpha\" (0 9 -3) + \"0.9snapshot\" (0 9 -4) + \"1.0-git\" (1 0 -4) + +See documentation for `version-separator' and `version-regexp-alist'." + (or (and (stringp ver) (> (length ver) 0)) + (error "Invalid version string: '%s'" ver)) + ;; Change .x.y to 0.x.y + (if (and (>= (length ver) (length version-separator)) + (string-equal (substring ver 0 (length version-separator)) + version-separator)) + (setq ver (concat "0" ver))) + (save-match-data + (let ((i 0) + (case-fold-search t) ; ignore case in matching + lst s al) + (while (and (setq s (string-match "[0-9]+" ver i)) + (= s i)) + ;; handle numeric part + (setq lst (cons (string-to-number (substring ver i (match-end 0))) + lst) + i (match-end 0)) + ;; handle non-numeric part + (when (and (setq s (string-match "[^0-9]+" ver i)) + (= s i)) + (setq s (substring ver i (match-end 0)) + i (match-end 0)) + ;; handle alpha, beta, pre, etc. separator + (unless (string= s version-separator) + (setq al version-regexp-alist) + (while (and al (not (string-match (caar al) s))) + (setq al (cdr al))) + (cond (al + (push (cdar al) lst)) + ;; Convert 22.3a to 22.3.1, 22.3b to 22.3.2, etc. + ((string-match "^[-_+ ]?\\([a-zA-Z]\\)$" s) + (push (- (aref (downcase (match-string 1 s)) 0) ?a -1) + lst)) + (t (error "Invalid version syntax: '%s'" ver)))))) + (if (null lst) + (error "Invalid version syntax: '%s'" ver) + (nreverse lst))))) + + +(defun version-list-< (l1 l2) + "Return t if L1, a list specification of a version, is lower than L2. + +Note that a version specified by the list (1) is equal to (1 0), +\(1 0 0), (1 0 0 0), etc. That is, the trailing zeros are insignificant. +Also, a version given by the list (1) is higher than (1 -1), which in +turn is higher than (1 -2), which is higher than (1 -3)." + (while (and l1 l2 (= (car l1) (car l2))) + (setq l1 (cdr l1) + l2 (cdr l2))) + (cond + ;; l1 not null and l2 not null + ((and l1 l2) (< (car l1) (car l2))) + ;; l1 null and l2 null ==> l1 length = l2 length + ((and (null l1) (null l2)) nil) + ;; l1 not null and l2 null ==> l1 length > l2 length + (l1 (< (version-list-not-zero l1) 0)) + ;; l1 null and l2 not null ==> l2 length > l1 length + (t (< 0 (version-list-not-zero l2))))) + + +(defun version-list-= (l1 l2) + "Return t if L1, a list specification of a version, is equal to L2. + +Note that a version specified by the list (1) is equal to (1 0), +\(1 0 0), (1 0 0 0), etc. That is, the trailing zeros are insignificant. +Also, a version given by the list (1) is higher than (1 -1), which in +turn is higher than (1 -2), which is higher than (1 -3)." + (while (and l1 l2 (= (car l1) (car l2))) + (setq l1 (cdr l1) + l2 (cdr l2))) + (cond + ;; l1 not null and l2 not null + ((and l1 l2) nil) + ;; l1 null and l2 null ==> l1 length = l2 length + ((and (null l1) (null l2))) + ;; l1 not null and l2 null ==> l1 length > l2 length + (l1 (zerop (version-list-not-zero l1))) + ;; l1 null and l2 not null ==> l2 length > l1 length + (t (zerop (version-list-not-zero l2))))) + + +(defun version-list-<= (l1 l2) + "Return t if L1, a list specification of a version, is lower or equal to L2. + +Note that integer list (1) is equal to (1 0), (1 0 0), (1 0 0 0), +etc. That is, the trailing zeroes are insignificant. Also, integer +list (1) is greater than (1 -1) which is greater than (1 -2) +which is greater than (1 -3)." + (while (and l1 l2 (= (car l1) (car l2))) + (setq l1 (cdr l1) + l2 (cdr l2))) + (cond + ;; l1 not null and l2 not null + ((and l1 l2) (< (car l1) (car l2))) + ;; l1 null and l2 null ==> l1 length = l2 length + ((and (null l1) (null l2))) + ;; l1 not null and l2 null ==> l1 length > l2 length + (l1 (<= (version-list-not-zero l1) 0)) + ;; l1 null and l2 not null ==> l2 length > l1 length + (t (<= 0 (version-list-not-zero l2))))) + +(defun version-list-not-zero (lst) + "Return the first non-zero element of LST, which is a list of integers. + +If all LST elements are zeros or LST is nil, return zero." + (while (and lst (zerop (car lst))) + (setq lst (cdr lst))) + (if lst + (car lst) + ;; there is no element different of zero + 0)) + + +(defun version< (v1 v2) + "Return t if version V1 is lower (older) than V2. + +Note that version string \"1\" is equal to \"1.0\", \"1.0.0\", \"1.0.0.0\", +etc. That is, the trailing \".0\"s are insignificant. Also, version +string \"1\" is higher (newer) than \"1pre\", which is higher than \"1beta\", +which is higher than \"1alpha\", which is higher than \"1snapshot\". +Also, \"-GIT\", \"-CVS\" and \"-NNN\" are treated as snapshot versions." + (version-list-< (version-to-list v1) (version-to-list v2))) + +(defun version<= (v1 v2) + "Return t if version V1 is lower (older) than or equal to V2. + +Note that version string \"1\" is equal to \"1.0\", \"1.0.0\", \"1.0.0.0\", +etc. That is, the trailing \".0\"s are insignificant. Also, version +string \"1\" is higher (newer) than \"1pre\", which is higher than \"1beta\", +which is higher than \"1alpha\", which is higher than \"1snapshot\". +Also, \"-GIT\", \"-CVS\" and \"-NNN\" are treated as snapshot versions." + (version-list-<= (version-to-list v1) (version-to-list v2))) + +(defun version= (v1 v2) + "Return t if version V1 is equal to V2. + +Note that version string \"1\" is equal to \"1.0\", \"1.0.0\", \"1.0.0.0\", +etc. That is, the trailing \".0\"s are insignificant. Also, version +string \"1\" is higher (newer) than \"1pre\", which is higher than \"1beta\", +which is higher than \"1alpha\", which is higher than \"1snapshot\". +Also, \"-GIT\", \"-CVS\" and \"-NNN\" are treated as snapshot versions." + (version-list-= (version-to-list v1) (version-to-list v2))) + +(defvar package--builtin-versions + ;; Mostly populated by loaddefs.el via autoload-builtin-package-versions. + (purecopy `((emacs . ,(version-to-list emacs-version)))) + "Alist giving the version of each versioned builtin package. +I.e. each element of the list is of the form (NAME . VERSION) where +NAME is the package name as a symbol, and VERSION is its version +as a list.") + +(defun package--description-file (dir) + (concat (let ((subdir (file-name-nondirectory + (directory-file-name dir)))) + (if (string-match "\\([^.].*?\\)-\\([0-9]+\\(?:[.][0-9]+\\|\\(?:pre\\|beta\\|alpha\\)[0-9]+\\)*\\)" subdir) + (match-string 1 subdir) subdir)) + "-pkg.el")) + + +;;; Misc. +(defconst menu-bar-separator '("--") + "Separator for menus.") + +;; The following statement ought to be in print.c, but `provide' can't +;; be used there. +;; http://lists.gnu.org/archive/html/emacs-devel/2009-08/msg00236.html +(when (hash-table-p (car (read-from-string + (prin1-to-string (make-hash-table))))) + (provide 'hashtable-print-readable)) + +;; This is used in lisp/Makefile.in and in leim/Makefile.in to +;; generate file names for autoloads, custom-deps, and finder-data. +(defun unmsys--file-name (file) + "Produce the canonical file name for FILE from its MSYS form. + +On systems other than MS-Windows, just returns FILE. +On MS-Windows, converts /d/foo/bar form of file names +passed by MSYS Make into d:/foo/bar that Emacs can grok. + +This function is called from lisp/Makefile and leim/Makefile." + (when (and (eq system-type 'windows-nt) + (string-match "\\`/[a-zA-Z]/" file)) + (setq file (concat (substring file 1 2) ":" (substring file 2)))) + file) + + +;;; subr.el ends here diff --git a/tests/examplefiles/tads3_example.t b/tests/examplefiles/tads3_example.t new file mode 100644 index 00000000..41881c93 --- /dev/null +++ b/tests/examplefiles/tads3_example.t @@ -0,0 +1,1248 @@ +#charset "utf-8" + +#include <adv3.h> +#include <en_us.h> + +extern function extern_function; +extern method extern_method; +extern function extern_function(a, b=a, c='<<a>>', d:, e:=1, f?, ...); +extern method extern_method(a, b=a, c='<<a>>', d:, e:=1, f?, [g]);; +extern class extern_class; +extern object extern_object; +intrinsic 't3vm' { }; +#ifndef PropDefAny +intrinsic class Object 'root-object/030004' { }; +#endif +object /**//**/ // /* \\ +#define Room Unthing + template [lst]; + +/* + * Quotations from "Le Roman de la Rose" are transcribed from MS. Douce 195, + * owned by Bodleian Library, University of Oxford + * (http://image.ox.ac.uk/show?collection=bodleian&manuscript=msdouce195). + */ + +versionInfo: GameID + IFID = '17d8efc3-07da-4dde-a837-ff7c4e386a77' + name = 'Pygmentalion' + byline = 'by David Corbett' + htmlByline = 'by <a href="mailto:corbett.dav\100husky.neu.edu">David + Corbett</a>' + version = '1' + authorEmail = 'David Corbett\040<corbett.dav\x40husky.neu.edu>' + desc = 'You have fallen in love with a statue\x2e' + htmlDesc = 'You have fallen in love with a statue\x2E' +; + +/* + * Pymalion fu ẽtailleꝛꝛes. + * Poᷣtrayãs en fus ⁊ en peꝛꝛeˢ + * En metaulx en os ⁊ en cyꝛes + * Et en touteˢ aultres matires. + * Quon peult a tel oeuure trouuer. + * Poᷣ ſon grant engin eſpꝛouuer. + * Car maiſtre en fu bien dire loz. + * Ainſi com poᷣ acquerre loz + * Se voult a poᷣtraire deduyꝛe + * Si fiſt vng ymage diuuyꝛe + * Et miſt au faire tel entente + * Quel fu ſi plaiſãt et ſi gente + * Quel ſembloit eſtre auſſi viue. + * Com la plus belle riens q̇ viue + * (MS. Douce 195, fol. 149r) + */ + +modify _init() +{ + ({: local r, r = randomize, r})(); + replaced(); +} + +gameMain: GameMainDef + initialPlayerChar: Actor { + desc = "You look the same as usual, but you feel unusually + sentimental. " + location = entrance + } + showIntro + { + "The statue is undeniably a masterpiece: the most skillful carving you + have ever done, and the most beautiful woman you have ever seen. + Unfortunately, she is also an inanimate block, and now you can neither + work nor rest for unrequitable love.\b + Once again you stumble into your studio, hoping and praying to find + your statue brought to life.\b + <b><<versionInfo.name>></b>\r\n + <<versionInfo.byline>>\b"; + } +; + +enum token token, tokOp, token; + +modify cmdTokenizer + rules_ = static + [ + ['whitespace', new RexPattern('%s+'), nil, &tokCvtSkip, nil], + ['punctuation', new RexPattern('[.,;:?!]'), tokPunct, nil, nil], + ['spelled number', + new RexPattern('<NoCase>(twenty|thirty|forty|fifty|sixty|' + + 'seventy|eighty|ninety)-' + + '(one|two|three|four|five|six|seven|eight|nine)' + + '(?!<AlphaNum>)'), + tokWord, &tokCvtSpelledNumber, nil], + ['spelled operator', new RexPattern( + '<NoCase>(plus|positive|minus|negat(iv)?e|not|inverse(%s+of)?|' + + 'times|over|divided%s+by|mod(ulo)?|and|xor|or|[al]?sh[lr])' + + '(?!<AlphaNum>)'), + tokOp, &tokCvtSpelledOperator, nil], + ['operator', R'[-!~+*/%&^|]|<<|>>>?', tokOp, nil, nil], + ['word', new RexPattern('<Alpha|-|&><AlphaNum|-|&|squote>*'), + tokWord, nil, nil], + ['string ascii-quote', R"""<min>([`\'"])(.*)%1(?!<AlphaNum>)""", + tokString, nil, nil], + ['string back-quote', R"<min>`(.*)'(?!%w)", tokString, nil, nil], + ['string curly single-quote', new RexPattern('<min>\u2018(.*)\u2019'), + tokString, nil, nil], + ['string curly double-quote', new RexPattern('<min>\u201C(.*)\u201D'), + tokString, nil, nil], + ['string unterminated', R'''([`\'"\u2018\u201C](.*)''', tokString, + nil, nil], + ['integer', new RexPattern('[0-9]+'), tokInt, nil, nil] + ] + replace tokCvtSpelledOperator(txt, typ, toks) + { + toks.append([rexReplace(R'%s+', txt.toLower(), '\\'), typ, txt]); + } +; + +/* Tokens */ + +/* + * Puiˢ li reueſt en maĩteˢ guiſes. + * Robeˢ faicteˢ ꝑ grãˢ maiſtriſeˢ. + * De biaulx dꝛaps de ſoye ⁊ de laĩe. + * Deſcarlate de tiretaine + * De vert de pers ⁊ de bꝛunecte + * De couleᷣ freſche fine ⁊ necte + * Ou moult a riches paneˢ miſes. + * Herminees vaires et griſes + * Puis les li roſte puis reſſaye. + * Cõmant li ſiet robbe de ſaye + * Sendaulx meloguins galebꝛunˢ. + * Indes vermeilz iaunes ⁊ bꝛunˢ. + * [...] + * Aultre foiz luy repꝛẽd courage. + * De tout oſter ⁊ mectre guindeˢ. + * Iaunes vermeilles vers ⁊ indeˢ. + * (MS. Douce 195, fol. 150r) + */ + +class Token: Achievement +{ + points = 1; + desc = "<<before_>><<desc_>><<after_>>"; + before = before = '', before_ + after = (after = '', after_) +} + +Token template inherited 'before_' 'after_' 'desc_'; + +#define DefineToken(name, before, after) name##Token: Token before after #@name + +DefineToken(builtin, '<font color=green>', '</font>'); +DefineToken(comment, '<i><font color=#408080>', '</font></i>'); +DefineToken(decorator, '<font color=#aa22ff>', '</font>'); +DefineToken(error, '<U><FONT COLOR=RED>', '</FONT></U>'); +DefineToken(escape, '<b><font color=#bb6622>', '</font></b>'); +DefineToken(float, '<u><font color=gray>', '</font></u>'); +DefineToken(keyword, '<b><font face=TADS-Sans color=green>', '</font></b>'); +DefineToken(label, '<font color=#A0A000>', '</font>'); +DefineToken(long, '<i><font color=gray>', '</font></i>'); +DefineToken(name, '<u>', '</u>'); +DefineToken(operator, '<b><font color=\"#AA22FF\">', '</font></b>'); +DefineToken(string, '<font color=\'#BA2121\'>', '</font>'); +DefineToken(whitespace, '<font color="bgcolor"bgcolor=\'text\'>', '</font>'); + +function highlightToken(tokenString) +{ + local token = [ + 'built in' -> builtinToken, + 'comment' -> commentToken, + 'decorator' -> decoratorToken, + 'error' -> errorToken, + 'escape' -> escapeToken, + 'float' -> floatToken, + 'keyword' -> keywordToken, + 'label' -> labelToken, + 'long' -> longToken, + 'name' -> nameToken, + 'operator' -> operatorToken, + 'string' -> stringToken, + 'white space' -> whitespaceToken, + * -> nil + ][tokenString.toLower()]; + if (!token) + return tokenString; + token.awardPointsOnce(); + return '<<token.before>><<tokenString>><<token.after>>'; +} + +string /**//**/ // /* \\ +#define Room Unthing + template <<highlight *>> highlightToken; + +/* Grammar for materials */ + +dictionary property material; +grammar adjWord(material): <material material>->adj_ : AdjPhraseWithVocab + getVocabMatchList(resolver, results, extraFlags) + { + return getWordMatches(adj_, &material, resolver, extraFlags, + VocabTruncated); + } + getAdjustedTokens() + { + return [adj_, &material]; + } +; + +/* Rooms and objects */ + ++ property location; + +entrance: Room 'Entrance' + "You are in the entrance to your studio. This is where you carve great + works of art, not that you have felt like making any lately. A door leads + outside, and the studio itself is to the north and the east. " + north = workbenchRoom + northeast = sinkRoom + east = altarRoom + south = door + out asExit(south) +; + ++ door: LockableWithKey, Door 'door' 'door' + "It is a simple wooden door. " + material = 'wood' 'wooden' + keyList = [key] + cannotOpenLockedMsg = '{The dobj/He} {is} locked. You cannot + <<highlight 'escape'>>! ' +; + +key: PresentLater, Key 'key' 'key' @altar + "It is a <<unless clean>>grimy<<end>> bronze key. <<if clean>>On it is \ + etched the word <q><<keyword>></q>. " + material = 'bronze' + clean = nil + keyword = (keyword = randomGreekWord(), targetprop) + dobjFor(Clean) { verify { } action { askForIobj(CleanWith); } } + dobjFor(CleanWith) + { + verify + { + if (clean) + illogicalAlready('{The dobj/He} {is} already clean. '); + } + action + { + gDobj.clean = true; + "{You/He} clean{s} {the dobj/him}, revealing an inscription. "; + } + } + dobjFor(Read) { verify { nonObvious; } } +; + +workbenchRoom: Room 'At the Workbench' + "This workbench, in the northwest part of the studio, was where you would + create works of art. Now you just come here to contemplate your + creation’s beauty and lament your hopeless situation.\b + The statue stands on a plinth beside the workbench. " + east = sinkRoom + southeast = altarRoom + south = entrance + getDestName(actor, origin) { return 'the workbench'; } +; + ++ workbench: Fixture, Surface + 'workbench/bench/material/materials/tool/tools' 'workbench' + "Normally, the workbench would be scattered with half-finished projects, + but now your tools and materials lie abandoned. " +; + ++ plinth: Fixture, Thing 'marble plinth/pedestal' 'plinth' + "It’s a smoothed block of marble about a cubit high. " +; + +replace grammar predicate(Screw): ' ': object; +replace grammar predicate(ScrewWith): ' ': object; ++ + statue: Fixture, Surface + '"creation\'s" beauty/carving/creation/galatea/statue/woman' 'statue' + "This is a<<if nameToken.scoreCount>>n untitled<<end>> statue of a woman + carved from <<if errorToken.scoreCount>>flawless <<end>> + <<if whitespaceToken.scoreCount>>milk-white <<end>>ivory. + <<if escapeToken.scoreCount || longToken.scoreCount>>Her + <<if longToken.scoreCount>>long <<end>>hair is done up in a + chignon<<if escapeToken.scoreCount>>, with a few strands falling down her + neck<<end>><<if floatToken.scoreCount>>, and \v<<else>>.<<end>><<end>> + <<if floatToken.scoreCount>>She radiates an aura of contrapposto grace. + <<end>><<if keywordToken.scoreCount>>\bYou wonder what she + <<if labelToken.scoreCount>>is going to<<else>>will<<end>> be like as a + woman. + <<if decoratorToken.scoreCount>>Maybe she’ll be a painter and expand + your business.<<end>> + <<if operatorToken.scoreCount>>Maybe she’ll have a head for figures + and will put the accounts in order.<<end>> + <<if builtinToken.scoreCount>>She’ll love you, obviously, but beyond + that you don’t know.<<end>><<end>> + <<if commentToken.scoreCount>>If only Aphrodite would bring her to life + without this silly puzzle about tokens and mirrors!<<end>> " + material = 'ivory' + propertyset 'is*' + { + propertyset 'H*' + { + im = nil\ + er = true; + } + It = true + } + iobjFor(PutOn) + { + check + { + if (gDobj not /**//**/ // /* \\ +#define Room Unthing + in (necklace, __objref(necklace, warn))) + "How rude! You don’t know what you were thinking. "; + } + } + iobjFor(GiveTo) remapTo(PutOn, DirectObject, IndirectObject) +; + ++++ necklace: Wearable + 'pearl necklace/string pearls' '<<highlight 'string'>> of pearls' + "This is a masterfully crafted pearl necklace. You hope the statue + won’t mind if you hold onto it for a while. " + initDesc = "You gave the statue this pearl necklace yesterday. " + isPlural = true +; + +altarRoom: Room 'At the Altar' + "Light from the window illuminates a crude altar. Until recently, this + corner was your bedroom. The rest of the studio lies north and west. " + north = sinkRoom + northwest = workbenchRoom + west = entrance + getDestName(actor, origin) { return 'the altar'; } +; + ++ window: Fixture 'window' 'window' + "It’s just a window above the altar. <<one of>>The space under the + window is blank; as an interior <<highlight 'decorator'>>, you can’t + help but think the wall would benefit from a bas-relief, but – + <i>sigh</i> &endash you are too lovelorn to wield the chisel. <<||>>The + wall right below it is a boring <<highlight 'white space'>>. <<stopping>>" +; + ++ altar: Fixture, Surface 'crude rough altar/banker/slab' 'altar' + "A rough marble slab lies on a wooden banker. In your rush to construct an + altar, you neglected the usual surface finish and friezes, but you pray at + it anyway. You are sure the gods will understand. " + material = 'marble' 'wood' 'wooden' + bulkCapacity = 1 + dobjFor(PrayAt) + { + verify { } + action() + { + /* + * Biaulx dieux diſt il tout ce poez. + * Sil voꝰ plaiſt ma requeſte oez + * [...] + * Et la belle q̇ mon cueᷣ emble + * Qui ſi bien yuoyꝛe reſſemble. + * Deuiengne ma loyal amye + * De fẽme ait coꝛps ame et vie + * (MS. Douce 195, fol. 151r) + */ + local offering; + foreach (offering in contents); + if (!keywordToken.scoreCount) + "<<one of>><q>O Aphrodite,</q> you say, <q>comforter of + hopeless lovers, hear my prayer! May she to whom I have given + my heart be given body, soul, and life. And a colorful + personality. And&mdash</q>\b + You are interrupted by a shimmering about the altar. As you + watch, it takes the form of a callipygian goddess.\b + <q>Mortal, I have heard your heart-felt and oft-repeated plea, + and I will take pity on you,</q> says Aphrodite. <q>If you give + me a token of your love as an offering, I will give you the + <<highlight 'keyword'>> of life. Speak this word in the + presence of a mirror, and I will grant your request.</q>\b + She fades away, adding, <q>As for her colorful personality, + just look around you.</q> <<or>><<stopping>>"; + else if (key.location) + "<q>O Aphrodite,</q> you say, <q>what am I supposed to do + again?</q>\bThe goddess reappears and reminds you to speak the + keyword of life at a mirror. <<one of>><q>What’s the + keyword, then?</q> <q>Gods help those who help themselves. + Figure it out yourself.</q><<or>><q>Why a mirror?</q> <q>I like + mirrors.</q><<purely at random>> "; + else if (offering == necklace) + { + "Aphrodite reappears. <q>A necklace! Perfect!</q> The necklace + disappears in a bright flash. When your eyes readjust, you see + a key lying in its place. "; + necklace.moveInto(nil); + key.makePresent(); + } + else if (+offering) + "Aphrodite reappears. She eyes <<offering.theNameObj>> + skeptically. <q><<one of>>No <<highlight 'comment'>>.<<or>>You + call <i>that</i> a token of love?<<or>>\^<<offering.aNameObj>>? + Really?<<or>>Come on, mortal, it’s not that + difficult!<<then at random>></q> "; + else + "<q>I heard you the first time,</q> says Aphrodite. <q>Prove + your devotion by offering a token of your love at the altar, + or the deal’s off.</q> "; + } + } + iobjFor(GiveTo) remapTo(PutOn, DirectObject, IndirectObject) +; + +aphrodite: Unthing + '(love) aphrodite/cytherea/god/goddess/venus love' 'Aphrodite' + '<<if gActor.canSee(altar)>>You can only pray to a god. + <<else>>You need an altar to interact with a god. ' + location = (gPlayerChar) + isProperName = true + isHer = true + iobjFor(GiveTo) + { + verify + { + illogical('She isn’t here. You’ll have to leave {the + dobj/him} somewhere she can find it. '); + } + } + dobjFor(PrayAt) maybeRemapTo(gActor.canSee(altar), PrayAt, altar) +; + +sinkRoom: Room 'Washroom' + "Sculpting marble is a dusty business. You use this sink to clean off after + a hard day’s work. Beside the sink is a small end table, and on the + wall is a calculator. The rest of the studio is south and west. " + south = altarRoom + southwest = entrance + west = workbenchRoom +; + +property level, overflowing; +export overflowing; +export level 'waterLevel'; ++ sink: Fixture '(auto) (mop) auto-sink/autosink/bowl/drain/faucet/sink' 'sink' + "This is a state-of-the-art mop sink with anti-miasmic coating and bronze + backsplash. It is so modern, there are no handles or other obvious ways to + turn it on.\b + <<if overflowing>>It is overflowing. + <<else unless level < 19500>>It is full to the brim with water. + <<otherwise if level >= 15000>>It is full of water. + <<otherwise unless level < 10000>>It is half full of water. + <<else if level >= 2000>>There is some water in the sink. + <<else if level > 0>>A small puddle has formed at the bottom of the sink. + <<otherwise>>It is empty. + <<if level <= -1.0e+2>>It looks like it hasn’t been used in a + <<highlight 'long'>> time. " + level = not in ([lst]) { return argcount; } + not = in() + overflowing = nil + current = self + setLevel(level:) + { + targetobj.current.overflowing = level == nil; + targetobj.current.level = min(level ?? 0, 20000); + if (sink.overflowing || sink.level > 0e+1) + sinkWater.makePresent(); + if (basin.overflowing || basin.level > 0e-1) + basinWater.makePresent(); + } + iobjFor(CleanWith) remapTo(CleanWith, DirectObject, sinkWater) +; + +++ sinkWater: PresentLater, Fixture + '(sink) water sink water' 'water' "<<sink.desc>>" + disambigName = 'water in the sink' + dobjFor(Drink) + { + verify { illogical('''{You're} not thirsty. '''); } + } + iobjFor(CleanWith) + { + preCond = [] + verify { + if (!location) + illogicalNow('There is no water in the sink. '); + if (!sink.overflowing && sink.level < 1e2) + illogicalNow('There is not enough water in the sink. '); + } + } +; + ++ table: Fixture, Surface 'small end bracket/table' 'table' + "<<first time>>Upon closer inspection, you see that \v<<only>>The table is + bracketed to the wall. " +; + +++ Readable '"operator\'s" manual' 'manual' + "<center ><<highlight 'Operator'>>’s Manual<\center>\b + <bq>To control the auto-sink, use the calculator add-on to enter the + desired volume of water. For example,\n + \t\t<<aHref('calculate 69 * 105', 'CALCULATE 69 TIMES 105')>>\n + to fill the basin with <<% ,d 0x69 * 0105>> kochliaria<!-- an ancient Greek + unit, < 5 ml >.\b + Warning: Do not use big numbers or divide by zero!<\\bq>\b" + dobjFor(Read) asDobjFor(Examine) +; + ++ calculator: Fixture, Thing 'button/buttons/calculator/screen' 'calculator' + "The calculator is <<highlight 'built in'>>to the wall beside the sink. It + has buttons for all the standard unary and binary operations. + <<if(screen)>>The screen reads <<screen>>" + screen = nil + literalMatch = '' +; + +method wrongContextMsg() +{ + return '<font face="TADS-Typewriter"><<highlight '<<'ERROR'>>'>> {{can\'t + use\ \"<<self.literalMatch>>\" in that context}}</font>. '; +} + +portico: OutdoorRoom 'Portico' + "Columns line the portico stretching east and west, and steps lead down to + the south. The door leads back in, and beside the door is a basin. A + <<highlight 'label'>> is affixed to the doorpost. " + north = (__objref(error, error)) + in asExit(north) + south: FakeConnector + { + "You begin moving away from the door, but then you remember the statue. + The gods won’t bring her to life if you give up this easily! + <<setMethod(&isConnectorApparent, {origin, actor: nil})>>" + } + east asExit(south) + west asExit(south) + down asExit(south) +; + +error: LockableWithKey, Door ->door 'door' 'door' @portico "<<door.desc>>" + keyList = (otherSide.keyList) +; + ++ Fixture 'column*columns' 'columns' + "There are six <<one of>>short columns with simple capitals<<or>>slender + columns with scrollwork in the capitals<<or>>tall columns with ornate + capitals<<sticky random>>. Above the architrave is a frieze depicting some + of your wares. <<first time>>The cornice overhangs the frieze a bit too + much, you think; perhaps you should shorten it. You try to concentrate on + the architecture of the portico, stoically ignoring what you cannot change, + but it doesn’t work. It never does. <<only>>" + isPlural = true +; + ++ Fixture, Readable 'label/doorpost' '<<highlight 'label'>>' + "The <<highlight 'label'>> says <q>Pygmentalion</q><<first time>> (which is + your <<highlight 'name'>>)<<only>>. " + dobjFor(Read) asDobjFor(Examine) +; + ++ basin: RestrictedContainer, Fixture + '(bird) basin/bath/birdbath/fountain/mosaic/pool/tile/tiles' 'basin' + "It is shallow but wide, and lined with tiles. It used to be a fountain, + but it stopped working after they installed the new sink. Something to do + with water pressure, no doubt. Now you just use it as a birdbath.\b + <<if overflowing>>Water is spilling over the sides in a turbulent flow. + <<else if level >= 19500>>It is full to the brim with water. You can see + your reflection quite clearly. Gods, you look a mess. + <<else if level >= 15000>>It is full of water. You can see your reflection. + <<else if level >= 10000>>It is half full. From the right angle, you can + make out a shadowy reflection of the columns, but nothing more. + <<else if level >= 2000>>There is some water in it, but you can still make + out the mosaic lining the basin. + <<else if level > 0>>A small puddle has formed at the bottom of the basin. + <<else>>It is empty. + <<if level <= -1.0e+2>>It looks as if it has never been filled. " + level = 0 + overflowing = nil + isMirror = (level >= 15000) + setLevel(level:) + { + delegated sink.setLevel(_: sourceTextOrder ? level: nil, level: level); + } + iobjFor(CleanWith) maybeRemapTo(basinWater.location, CleanWith, + DirectObject, basinWater) +; + +++ basinWater: PresentLater, Fixture '(basin) water basin water' 'water' + "<<basin.desc>>" + disambigName = 'water in the basin' + dobjFor(Drink) + { + verify + { + illogical('Drinking from a birdbath might not be the best idea. '); + } + } + iobjFor(CleanWith) + { + preCond = [touchObj] + verify { + illogical('Washing something in a birdbath is unlikely to get it + clean. '); + } + } +; + +++ feather: PresentLater, Thing + '(bird) (dove) (pigeon) (turtle) (turtle-dove) (turtledove) feather' + 'feather' "It’s a turtle-dove feather: an auspicious omen! " + initSpecialDesc = "<<one of>>A little brown bird is splashing around in the + basin. When it notices you, it ruffles its feathers, one of which falls + out, and flies out between the columns. <<or>>A feather is + <<if basin.overflowing || basin.level > 0>><<highlight 'float'>>ing + <<else>>lying <<end>> in the basin. <<stopping>>" +; + +/* Water */ + +trickling(water) multimethod +{ + if (sink.overflowing) + { + dirs: for (local dir in Direction.allDirections) + { + if (dir.ofKind(RelativeDirection)) + continue; + if (dir.ofKind(ShipboardDirection)) + continue dirs; + if (water.eventualLocation.(dir.dirProp) == __objref(entrance)) + return 'trickling <<dir.name>>'; + } + } + return 'a stagnant puddle'; +} + +class Water:PresentLater,Fixture'(floor) (ground) water puddle water''water' + "The water on the floor is <<trickling(self)>>. " + disambigName = 'water on the floor' + specialDesc = "The floor is covered with water. " + dobjFor(Drink) + { + preCond = [touchObj] + verify { } + check { failCheck('{You\'re} not thirsty. '); } + } + iobjFor(CleanWith) + { + preCond = [touchObj] + verify { illogical('The water on the ground is too dirty. '); } + } +; + +Water template +location | ~location "specialDesc"? inherited; +Water +altarRoom; +Water +sinkRoom { ;; }; +Water { +workbenchRoom }; + +entranceWater: Water +entrance + "<<if sink.overflowing>>At your feet, all the water from the sink flows + into a <<%-o 02>>-dactyl slit in the baseboard. <<else>><<inherited>>" + vocabWords = 'water baseboard/puddle/slit water' +; +trickling(entranceWater w) +{ + return sink.overflowing ? 'trickling into the wall' : inherited<*>(w); +} + +porticoWater: Water ~portico; +trickling(porticoWater w) +{ + return basin.overflowing ? 'trickling down the stairs' : inherited<*>(w); +} + +/* Calculating */ + +;;;class is: Exception { finalize { } };;; // InvalidSpecificationError + +DefineLiteralAction(Calculate) + checkAction() + { + if (defined(calculator) && !gActor.canTouch(calculator)) + { + { gActor.failCheck('{You/He} {can\'t} do that kind of math in + {your} head. '); } + } + } + execAction() + { + local op = function(...) { throw new is(); }, a, b; + local opString = (literalMatch, literalMatch); + if (numMatch) + goto binary; + switch (opString) + { + case '!': + case 'not': + opString = '!'; + op = {x : !toInteger('<<%_\u0030[1]5.3\170x>>', 16)}; + break; + case '+': + case 'plus': + case 'positive': + opString = '+'; + op = {self_ : self_}; + break; + case '-': + case 'minus': + case 'negate': + case 'negative': + opString = '−'; + op = {x : -x}; + break; + case '~': + case 'inverse': + case 'inverse\\of': + opString = '~'; + op = {x : ~x}; + break; + } + goto doCalculation; + binary: binaryOp: + switch (opString) + { + case '+': + case 'plus': + opString = '+'; + op = {a, b : +a+++b}; + break binaryOp; + case '-': + case 'minus': + opString = '−'; + op = {a, b : -b-- - -a}; + break; + case '*': + case 'times': + opString = '×'; + op = new function(a, b) { return a * b; }; + break; + case '/': + case 'over': + case 'divided\\by': + opString = '/'; + op = function(a, b) { return a / b; }; + break; + case '%': + case 'mod': + case 'modulo': + opString = 'mod'; + op = function(a, b, multimethod=b) { return a % multimethod; }; + break; + case '\<<': + case 'shl': + case 'ashl': + case 'lshl': + opString = '<<'; + op = {a, b, c? : a << b}; + break; + case '&': + case 'and': + opString = '&'; + op = {a, b : local badness = a, local token = b, badness & token}; + break; + case '^': + case 'xor': + opString = '^'; + op = {a, b, c? : a ^ b}; + break; + case '|': + case 'or': + opString = '|'; + op = {a, b : a | b}; + break; + case '>\>': + case 'shr': + case 'ashr': + opString = '>>'; + op = {a, b : toInteger('<<(a >> b)>>')}; + break; + case '>>>': + case 'lshr': + opString = '>>>'; + op = {a, b : b ? invokee(a >>> 1, --b) : a}; + break; + } + opString = ' <<opString>> '; + doCalculation: + "The calculator outputs "; + try + { + a = numMatch ? numMatch.getval(colon : nil) : nil; + b = numMatch2.getval(); + local result = toInteger(numMatch ? op(a, b) : op(b)); + calculator.setMethod(&screen, method() + { + return '<font face="TADS-Typewriter"><<a>><<opString>><<b>> = + <<%d result>></font>. '; + }); + local oldLevel = sink.level; + sink.current.setLevel(level: result); + "<<calculator.screen()>> + <<if sink.current == basin>>The sink gurgles and the pipes rattle. + <<else if sink.level == oldLevel>>The sink gurgles. + <<else if sink.level <= 0 && oldLevel <= 0>>The pipes rattle for a + moment. + <<else if sink.level <= 0>>All the water drains from the sink. + <<else if oldLevel <= 0>>The sink begins to fill with water. + <<else if sink.level < oldLevel - 0xabc>>Some of the water drains + from the sink. + <<else if sink.level < oldLevel>>The water level drops slightly. + <<else if oldLevel < sink.level - 0XABC>>Water splashes into the + sink for a few seconds. + <<else if oldLevel < sink.level>>Water dribbles from the faucet. "; + } + catch (is in) + { + calculator.literalMatch = literalMatch; + calculator.setMethod(&screen, &wrongContextMsg); + "<<calculator.screen()>>"; + } + catch (RuntimeError e) + { + calculator.setMethod(&screen, new method + { + return '<font face=\"TADS-Typewriter\"><<highlight 'ERROR'>> + {{<<e.exceptionMessage>>}}</font>.\b'; + }); + "<<calculator.screen()>>"; + switch (e.errno_) + { + case 2008: // division by zero + "<<if sink.current == sink + && (sink.level > 0 || sink.overflowing)>>The water in the + sink is sucked down the drain. + <<else if basin.level > 0 || basin.overflowing>>Water comes up + from the drain and <<if basin.overflowing>>spills over + the edges of<<else>>begins to fill<<end>> the sink. + <<else>>The sink gurgles and the pipes rattle. "; + sink.current = sink.current == sink ? basin : sink; + local _tmp = sink.level; + sink.level = basin.level; + basin.level = _tmp; + _tmp = sink.overflowing; + sink.overflowing = basin.overflowing; + basin.overflowing = _tmp; + if (!sink.current.overflowing) + break; + // fall through + case 2023: // numeric overflow + if (!sink.current.overflowing) + "<<if sink.current == sink>>High-pressure water streams + from the faucet, filling the sink and spilling over the + edge. Rivulets begin running down the slight gradient of + the floor. <<else>>The pipes shake loudly. "; + forEachInstance(Water, function(w) { + if ((w.eventualLocation == portico) == + (sink.current == basin)) + w.makePresent(); + }); + sink.current.setLevel(level: nil); + break; + default: + throw e; + } + } + if (!gPlayerChar.hasSeen(feather)) + { + feather.makePresentIf(basin.isMirror); + feather.moved = nil; + } + } +; + +VerbRule(Calculate) + ('c' | 'calculate' | 'enter' | 'eval' | 'evaluate') (()|(singleNumber|)) + (tokOp->literalMatch | '!'->literalMatch) numberPhrase -> numMatch2 + : CalculateAction + verbPhrase = 'calculate/calculating (what) (how) (what)' +; + +/* Cleaning */ + +modify VerbRule(Clean) + [ /**//**/ // /* \\ +#define Room Unthing + badness 500] ('clean' | 'wash') dobjList: +; + +grammar predicate(CleanIn): + ('clean' | 'wash') dobjList ('at' | 'in' | 'with') singleIobj + : CleanWithAction + verbPhrase = 'clean/cleaning (what) (in what)' + askIobjResponseProd = inSingleNoun + omitIobjInDobjQuery = true +; + +/* Prayer */ + +VerbRule(Pray) + [badness 500] 'pray' singleDobj + : PrayAtAction + verbPhrase = 'pray/praying (at what)' +; + +VerbRule(PrayAt) + 'pray' ('at' | 'to') singleDobj + : PrayAtAction + verbPhrase = 'pray/praying (at what)' + askDobjResponseProd = singleNoun +; + +DefineTAction(PrayAt); +modify Thing + dobjFor(PrayAt) + { + verify + { + illogical('{You/He} {cannot} pray at {that dobj/him}. '); + } + } +; + +/* Extended grammar for 'in' and 'out' */ + +modify grammar directionName(in): 'in' | 'inside': + dir = inDirection +; +modify /**//**/ // /* \\ +#define Room Unthing + grammar directionName(out): 'out' | 'outside': + dir = outDirection +; + +/* Speech */ + +DefineLiteralAction(Say) + execAction + { + local literal = getLiteral().toLower(); + if (literal is in ('xyzzy', 'plugh')) + tryImplicitActionMsg(&silentImplicitAction, Xyzzy); + else if (literal != key.keyword) + "Nothing happens. "; + else if (literal not in ()) + { + if (gActor.location == portico && basin.isMirror) + { + if (feather.location == basin) + "The air above the basin shimmers, and the feather bobs on + the rippling water. After a moment, the shimmering + disappears."; + else + { + /* + * Venus q̇ la pꝛiere ouyt + * [...] + * A lymage ẽuoya loꝛs lame. + * Si deuĩt ſi treſbelle dame. + * Quoncq̄s en toute la contree. + * Not len ſi belle encontree. + * [...] + * Doulx amys aĩs ſuy vꝛ̄e amye. + * Pꝛeſte de voſtre compaignye. + * Receuoir ⁊ mamoᷣ voꝰ offre. + * Sil voꝰ plaiſt receuoir tel offre. + * (MS. Douce 195, fol. 151v) + */ + "The air above the basin shimmers for a moment. You hear + the door opening behind you. Turning around, you see a + woman who looks suspiciously like your statue, except not + the color of marble.\b + <q>Hello, world,</q> she says. <q>It’s nice to be + alive at last! Hello, dearest Pygmentalion.</q>\b + Ah, what beauty! What mastery of syntax! Praise be to + Aphrodite! "; + finishGameMsg(ftVictory, + [finishOptionUndo, finishOptionFullScore]); + } + } + else + "Nothing happens. <<if keywordToken.scoreCount>>Aphrodite said + you would need a mirror. <<end>>"; + } + } +; + +VerbRule(Say) + ('say' | 'shout') singleLiteral + : SayAction + verbPhrase = 'say/saying (what)' +; + +VerbRule(SayTo) + ('say' | 'shout') singleLiteral ('at' | 'to') singleIobj + : SayAction + verbPhrase = 'say/saying (what) (to what)' +; + +/**/ #if /* Revere the basileus. */ 0 \ + // Expel the barbarian. +; + #ifndef __DEBUG +; + #define __DEBUG +; +# else +; +#if 1 +; + #define DEBUG__ +; +#endif +; + #endif +;\\ +#endif +/* +#endif +?*/ +//\\ +#endif +''' +#endif +'\'''' +#endif +\\''' +""" +#endif +"\"""" +#endif +\\""" +' +#endif +\' +#endif +\\' +" +#endif +\" +#endif +\\" +'''<<'<<' +#endif +'>>'>> +#endif +''' +"""<<'<<' +#endif +'>>'>> +#endif +""" +'<<'<<' +#endif +'>>'>> +#endif +' +"<<'<<' +#endif +'>>'>> +#endif +"//" +\ + # endif +; +dictionary barbarianDict; +transient xyzzy: object; +DefineIAction(Xyzzy) + execAction + { + "Only a barbarian could pronounce such a word. "; + local oldSay = t3SetSay({str : nil}); + try + { + new transient Vector([ + '<<one of>><< cycling >>', + '<<one of>><< at random>>', + '<<one of>><<then purely at random>>', + '<<one of>><<as decreasingly likely outcomes>>', + '<<one of>><< shuffled>>', + '<<one of>><< half shuffled>>', + '<<one of>><<then shuffled>>', + '<<one of>><<then half shuffled>>']); + '''''<font x= color=red bgcolor='silver' face="TADS-Sans" + size=\'+1\' x=\"x\">{can't}</font>\'''' '' ''''; + """""<font x= color=red bgcolor='silver' face="TADS-Sans" + size=\'+1\' x=\"x\">{can't}</font>\"""" "" """"; + '<font x= color=red face="TADS-Sans" size=\'+1\' + x=\"x\">{can\'t}</font>\''; + "<font x= color=red bgcolor='silver' size=\'+1\' + x=\"x\">{can\'t}</font>\""; + '''''<font <<'color=red'>> bgcolor<<'='>>silver + face=<<'"TADS-Sans"'>>>{ca<<'n\''>>t}</font>\'''' '' ''''; + """""<font <<'color=red'>> bgcolor<<'='>>silver + face=<<'"TADS-Sans"'>>>{ca<<'n\''>>t}</font>\"""" "" """"; + '<font <<'color=red'>> bgcolor<<'='>>silver + face=<<'"TADS-Sans"'>>>{ca<<'n\''>>t}</font>\''; + "<font <<'color=red'>> bgcolor<<'='>>silver + face=<<'"TADS-Sans"'>>>{ca<<'n\''>>t}</font>\""; + '''<s a1={\.}a a2=a{\>} a3=a{\>}a b1='{\>}b' b2='b{\>}' b3='b{\>}b' + c1="c{\>}" c2="{\>}c" c3="c{\>}c" d1=\'d{\>}\' d2=\'{\>}d\' + d3=\'d{\>}d\' e1=\"e{\>}\" e2=\"{\>}e\" e3=\"e{\>}e\"></s>'''; + """<s a1={\.}a a2=a{\>} a3=a{\>}a b1='{\>}b' b2='b{\>}' b3='b{\>}b' + c1="c{\>}" c2="{\>}c" c3="c{\>}c" d1=\'d{\>}\' d2=\'{\>}d\' + d3=\'d{\>}d\' e1=\"e{\>}\" e2=\"{\>}e\" e3=\"e{\>}e\"></s>"""; + '<s a1={\.}a a2=a{\>} a3=a{\>}a c1="c{\>}" c2="{\>}c" c3="c{\>}c" + d1=\'d{\>}\' d2=\'{\>}d\' d3=\'d{\>}d\' e1=\"e{\>}\" e2=\"{\>}e\" + e3=\"e{\>}e\"></s>'; + "<s a1={\.}a a2=a{\>} a3=a{\>}a b1='{\>}b' b2='b{\>}' b3='b{\>}b' + d1=\'d{\>}\' d2=\'{\>}d\' d3=\'d{\>}d\' e1=\"e{\>}\" e2=\"{\>}e\" + e3=\"e{\>}e\"></s>"; + '''{a<<1>>b}'''; """{a<<1>>b}"""; '{a<<1>>b}'; "{a<<1>>b}"; + '''<s a<<'='>>'1' b<<'='>>"2" c<<'='>>\'3\' d<<'='>>\"4\" + <<'e'>>=5 f=6' g=7">'''; + """<s a<<'='>>'1' b<<'='>>"2" c<<'='>>\'3\' d<<'='>>\"4\" + <<'e'>>=5 f=6' g=7">"""; + '<s b<<'='>>"2" c<<'='>>\'3\' d<<'='>>\"4\" <<'e'>>=5 g=7">'; + "<s a<<'='>>'1' c<<'='>>\'3\' d<<'='>>\"4\" <<'e'>>=5 f=6'>"; + '''<s a=v\\ a=v\ v\><s a='{'}'\><s a="{"}"\>'''; + """<s a=v\\ a=v\ v\><s a='{'}'\><s a="{"}"\>"""; + '<s a=v\\ a=v\ v\><s a=\'{\'}\'\><s a="{"}"\>'; + "<s a=v\\ a=v\ v\><s a='{'}'\><s a=\"{\"}\"\>"; + '''<font color='purple>igram</font>'''; '''<t a={'''; '''}'''; + '''<font color="purple>igram</font>'''; '''<t a='{'''; '''}'''; + '''<font color=\'purple>igram</font>'''; '''<t a="{'''; '''}'''; + '''<font color=\"purple>igram</font>'''; + """<font color='purple>igram</font>"""; """<t a={"""; """}"""; + """<font color="purple>igram</font>"""; """<t a='{"""; """}"""; + """<font color=\'purple>igram</font>"""; """<t a=\"{"""; """}"""; + """<font color=\"purple>igram</font>"""; + '<font color="purple>igram</font>'; '<t a={'; '}'; + '<font color=\'purple>igram</font>'; '<t a=\'{'; '}'; + '<font color=\"purple>igram</font>'; '<t a="{'; '}'; + "<font color=\"purple>igram</font>"; "<t a={"; "}"; + "<font color='purple>igram</font>"; "<t a='{"; "}"; + "<font color=\'purple>igram</font>"; "<t a=\"{"; "}\""; + '''<xmp a=v>&\x26<b><\xmp></xmp a=v>'''; + """<xmp a=v>&\x26<b><\xmp></xmp a=v>"""; + '<xmp a=v>&\x26<b><\xmp></xmp a=v>'; + "<xmp a=v>&\x26<b><\xmp></xmp a=v>"; + '''<xmp a=v>&\x26<b><\xmp><\Xmp a=v>'''; + """<xmp a=v>&\x26<b><\xmp><\Xmp a=v>"""; + '<xmp a=v>&\x26<b><\xmp><\Xmp a=v>'; + "<xmp a=v>&\x26<b><\xmp><\Xmp a=v>"; + '''<xmp a=v>&\x26<b><\xmp><\\xmp a=v>'''; + """<xmp a=v>&\x26<b><\xmp><\\xmp a=v>"""; + '<xmp a=v>&\x26<b><\xmp><\\xmp a=v>'; + "<xmp a=v>&\x26<b><\xmp><\\xmp a=v>"; + '''<xmp>'''; """<xmp>"""; '<xmp>'; "<xmp>"; + '''<listing a=v>&\x26<b><listing><xmp></listing a=v>'''; + """<listing a=v>&\x26<b><listing><xmp></listing a=v>"""; + '<listing a=v>&\x26<b><listing><xmp></listing a=v>'; + "<listing a=v>&\x26<b><listing><xmp></listing a=v>"; + '''<listing a=v>&\x26<b><listing><xmp><\listing a=v>'''; + """<listing a=v>&\x26<b><listing><xmp><\listing a=v>"""; + '<listing a=v>&\x26<b><listing><xmp><\listing a=v>'; + "<listing a=v>&\x26<b><listing><xmp><\listing a=v>"; + '''<listing a=v>&\x26<b><listing><xmp><\\listing a=v>'''; + """<listing a=v>&\x26<b><listing><xmp><\\listing a=v>"""; + '<listing a=v>&\x26<b><listing><xmp><\\listing a=v>'; + "<listing a=v>&\x26<b><listing><xmp><\\listing a=v>"; + '''<listing>'''; """<listing>"""; '<listing>'; "<listing>"; + } + finally + { + t3SetSay(oldSay); + } + } +; + +VerbRule(Xyzzy) + "xyzzy" | "plugh" * + : XyzzyAction + verbPhrase = 'babble/talking like a barbarian' +; + +randomGreekWord() +{ + local vowels = ['a', 'e', 'e', 'i', 'o', 'y', 'o']; + local consonants = ['p', 't', 'k', 'b', 'd', 'g', 's', 'm', 'n', 'l', 'r']; + local clusters = + ['pn', 'pl', 'pr', 'tm', 'tr', 'kn', 'kl', 'kr', 'bl', 'br']; + local ends = consonants - ['b', 'd', 'g']; + local word; + local retries = 0; + for (local r in 0 .. -1 step -1) + { + for ((r), local i = 0, local j = 2; i < j; ++i, --j) + { + for (local s = 0, local n in [90, 30, 10]; ; --s) + retries -= s * n; + } + } + retries *= 2; + retries >>= 1; + retries /= 2; + retries <<= 1; + retries >>>= 2; + retries %= 16; + retries &= ~1; + retries |= 2; + retries ^= retries ^ retries; + do + { + word = rand('[ptkbdgsm]?'); + for (local i in 0 .. __TADS3) + word += concat(rand(rand('', clusters, consonants)), rand('"h"?'), + rand(vowels...), rand('','', 'i', 'u', rand(ends))); + word += rand('"s"?'); + word = rexReplace(R'^[pk](?![tnlrhaeioy]|[tnlr]h?[^aeioy])', word, ''); + word = rexReplace(R'^b(?![dlrhaeioy]|[dlr]h?[^aeioy])', word, ''); + word = rexReplace(R'^g(?![nlrhaeioy]|[nlr]h?[^aeioy])', word, ''); + word = rexReplace(R'^t(?![mrhaeioy]|[mlr]h?[^aeioy])', word, ''); + word = rexReplace(R'^d(?![rhaeioy]|rh?[^aeioy])', word, ''); + word = rexReplace(R'^m(?![nhaeioy]|nh?[^aeioy])', word, ''); + word = rexReplace(R'^[^aeioy]h?(([^haeioy]h?){2})', word, '%1'); + word = rexReplace(R'[ptkbdgs]([ptkbdg][^haeioy])', word, '%1'); + word = rexReplace(R'([mnlr])h', word, 'h%1'); + word = rexReplace(R'(?<!(^|[ptk]))h', word, ''); + word = rexReplace(R'^h(?![aeioy])', word, ''); + word = rexReplace(R'h(?=.*h)', word, ''); + word = rexReplace(R'(?<=^|r)r', word, 'rh'); + word = rexReplace(R'([iy]+)[iu]', word, '%1'); + word = rexReplace(R'nl', word, 'll'); + word = rexReplace(R'n(?=[pbm])', word, 'm'); + word = rexReplace(R'(?<.)m(?=[tdn])', word, 'n'); + word = rexReplace(R'pb|bp', word, 'pp'); + word = rexReplace(R'td|dt', word, 'tt'); + word = rexReplace(R'kg|gk', word, 'kk'); + word = rexReplace(R'bs', word, 'ps'); + word = rexReplace(R'ds|sd', word, 'z'); + word = rexReplace(R'gs', word, 'ks'); + word = rexReplace(R'ts', word, 'ss'); + word = rexReplace(R'[^pkaeioyusnr]+(s?)$', word, '%1'); + word = rexReplace(R'[pk]+$', word, ''); + word = rexReplace(R'(.h?)%1{2,}', word, '%1%1'); + word = rexReplace(R'^(.h?)%1', word, '%1'); + word = rexReplace(R'(.h?)%1$', word, '%1'); + word = rexReplace(R'^y', word, 'hy'); + word = rexReplace(R'([ptk])([ptk])h', word, '%1h%2h'); + word = rexReplace(R'([ptk])h%1h', word, '%1%1h'); + word = rexReplace(R'ks', word, 'x'); + word = rexReplace(R'gg', word, 'kg'); + word = rexReplace(R'kh', word, 'ch'); + } while (retries-- && (word.length() < 4 || !rexSearch( + new RexPattern('^(eu|hy|[pgm]n|bd|tm|rh)|(.h.|pp|kc|rr)h|ch([^aeioy])|' + + '([^aeioy])y([^aeioy])$|(ps|x|o[ius])$'), word))); + return word; +} diff --git a/tests/examplefiles/test.R b/tests/examplefiles/test.R index 54325339..1dd8f64b 100644 --- a/tests/examplefiles/test.R +++ b/tests/examplefiles/test.R @@ -33,10 +33,11 @@ NA_foo_ <- NULL 123456.78901 123e3 123E3 -1.23e-3 -1.23e3 -1.23e-3 -## integer constants +6.02e23 +1.6e-35 +1.E12 +.1234 +## integers 123L 1.23L ## imaginary numbers @@ -80,7 +81,7 @@ repeat {1+1} ## Switch x <- 3 switch(x, 2+2, mean(1:10), rnorm(5)) -## Function, dot-dot-dot, return +## Function, dot-dot-dot, return, sum foo <- function(...) { return(sum(...)) } @@ -151,3 +152,34 @@ world!' ## Backtick strings `foo123 +!"bar'baz` <- 2 + 2 + +## Builtin funcitons +file.create() +gamma() +grep() +paste() +rbind() +rownames() +R.Version() +R.version.string() +sample() +sapply() +save.image() +seq() +setwd() +sin() + +## Data structures +servo <- matrix(1:25, nrow = 5) +numeric() +vector(servo) +data.frame() +list1 <- list(time = 1:40) +# multidimensional array +array(c(c(c(2,300,4),c(8,9,0)),c(c(5,60,0),c(66,7,847))), dim=c(3,2,2)) + +## Namespace +library(ggplot2) +require(plyr) +attach(cars) +source("test.R") diff --git a/tests/examplefiles/test.agda b/tests/examplefiles/test.agda index d930a77b..f6cea91c 100644 --- a/tests/examplefiles/test.agda +++ b/tests/examplefiles/test.agda @@ -12,11 +12,18 @@ open import Data.List hiding ([_]) open import Data.Vec hiding ([_]) open import Relation.Nullary.Core open import Relation.Binary.PropositionalEquality using (_≡_; refl; cong; trans; inspect; [_]) + renaming (setoid to setiod) open SemiringSolver {- this is a {- nested -} comment -} +postulate pierce : {A B : Set} → ((A → B) → A) → A + +instance + someBool : Bool + someBool = true + -- Factorial _! : ℕ → ℕ 0 ! = 1 diff --git a/tests/examplefiles/test.apl b/tests/examplefiles/test.apl new file mode 100644 index 00000000..26ecf971 --- /dev/null +++ b/tests/examplefiles/test.apl @@ -0,0 +1,26 @@ +∇ R←M COMBIN N;D;E;F;G;P + ⍝ Returns a matrix of every possible + ⍝ combination of M elements from the + ⍝ vector ⍳N. That is, returns a + ⍝ matrix with M!N rows and N columns. + ⍝ + E←(⍳P←N-R←M-1)-⎕IO + D←R+⍳P + R←(P,1)⍴D + P←P⍴1 + L1:→(⎕IO>1↑D←D-1)⍴0 + P←+\P + G←+\¯1↓0,F←⌽P + E←F/E-G + R←(F/D),R[E+⍳⍴E;] + E←G + →L1 +∇ + +∇ R←M QUICKEXP N + ⍝ Matrix exponentiation + B ← ⌊ 1 + 2 ⍟ N + V ← (B ⍴ 2) ⊤ N + L ← ⊂ M + R ← ⊃ +.× / V / L ⊣ { L ← (⊂ A +.× A ← ↑L) , L }¨ ⍳ B-1 +∇ diff --git a/tests/examplefiles/test.cyp b/tests/examplefiles/test.cyp new file mode 100644 index 00000000..37465a4d --- /dev/null +++ b/tests/examplefiles/test.cyp @@ -0,0 +1,123 @@ +//test comment +START a = node(*) +MATCH (a)-[:ACTED_IN]->(m)<-[:DIRECTED]-(d) +RETURN a.name, m.title, d.name; + +START a = node(*) +MATCH (a)-[:ACTED_IN]->(m)<-[:DIRECTED]-(d) +WITH d,m,count(a) as Actors +WHERE Actors > 4 +RETURN d.name as Director,m.title as Movie, Actors ORDER BY Actors; + +START a=node(*) +MATCH p=(a)-[:ACTED_IN]->(m)<-[:DIRECTED]-(d) +return p; + +START a = node(*) +MATCH p1=(a)-[:ACTED_IN]->(m), p2=d-[:DIRECTED]->(m) +WHERE m.title="The Matrix" +RETURN p1, p2; + +START a = node(*) +MATCH (a)-[:ACTED_IN]->(m)<-[:DIRECTED]-(d) +WHERE a=d +RETURN a.name; + +START a = node(*) +MATCH (a)-[:ACTED_IN]->(m)<-[:DIRECTED]-(d) +WHERE a=d +RETURN a.name; + +START a=node(*) +MATCH (a)-[:ACTED_IN]->(m)<-[:DIRECTED]-(d) +RETURN a.name, d.name, count(*) as Movies,collect(m.title) as Titles +ORDER BY (Movies) DESC +LIMIT 5; + +START keanu=node:node_auto_index(name="Keanu Reeves") +RETURN keanu; + +START keanu=node:node_auto_index(name="Keanu Reeves") +MATCH (keanu)-[:ACTED_IN]->(movie) +RETURN movie.title; + +START keanu=node:node_auto_index(name="Keanu Reeves") +MATCH (keanu)-[r:ACTED_IN]->(movie) +WHERE "Neo" in r.roles +RETURN DISTINCT movie.title; + +START keanu=node:node_auto_index(name="Keanu Reeves") +MATCH (keanu)-[:ACTED_IN]->()<-[:DIRECTED]-(director) +RETURN director.name; + +START keanu=node:node_auto_index(name="Keanu Reeves") +MATCH (keanu)-[:ACTED_IN]->(movie)<-[:ACTED_IN]-(n) +WHERE n.born < keanu.born +RETURN DISTINCT n.name, keanu.born ,n.born; + +START keanu=node:node_auto_index(name="Keanu Reeves"), + hugo=node:node_auto_index(name="Hugo Weaving") +MATCH (keanu)-[:ACTED_IN]->(movie) +WHERE NOT((hugo)-[:ACTED_IN]->(movie)) +RETURN DISTINCT movie.title; + +START a = node(*) +MATCH (a)-[:ACTED_IN]->(m) +WITH a,count(m) as Movies +RETURN a.name as Actor, Movies ORDER BY Movies; + +START keanu=node:node_auto_index(name="Keanu Reeves"),actor +MATCH past=(keanu)-[:ACTED_IN]->()<-[:ACTED_IN]-(), + actors=(actor)-[:ACTED_IN]->() +WHERE hasnt=actors NOT IN past +RETURN hasnt; + +START keanu=node:node_auto_index(name="Keanu Reeves") +MATCH (keanu)-[:ACTED_IN]->()<-[:ACTED_IN]-(c), + (c)-[:ACTED_IN]->()<-[:ACTED_IN]-(coc) +WHERE NOT((keanu)-[:ACTED_IN]->()<-[:ACTED_IN]-(coc)) +AND coc > keanu +RETURN coc.name, count(coc) +ORDER BY count(coc) DESC +LIMIT 3; + +START kevin=node:node_auto_index(name="Kevin Bacon"), + movie=node:node_auto_index(name="Mystic River") +MATCH (kevin)-[:ACTED_IN]->(movie) +RETURN DISTINCT movie.title; + +CREATE (n + { + title:"Mystic River", + released:1993, + tagline:"We bury our sins here, Dave. We wash them clean." + } + ) RETURN n; + + +START movie=node:node_auto_index(title="Mystic River") +SET movie.released = 2003 +RETURN movie; + +start emil=node:node_auto_index(name="Emil Eifrem") MATCH emil-[r]->(n) DELETE r, emil; + +START a=node(*) +MATCH (a)-[:ACTED_IN]->()<-[:ACTED_IN]-(b) +CREATE UNIQUE (a)-[:KNOWS]->(b); + +START keanu=node:node_auto_index(name="Keanu Reeves") +MATCH (keanu)-[:KNOWS*2]->(fof) +WHERE keanu <> fof +RETURN distinct fof.name; + +START charlize=node:node_auto_index(name="Charlize Theron"), + bacon=node:node_auto_index(name="Kevin Bacon") +MATCH p=shortestPath((charlize)-[:KNOWS*]->(bacon)) +RETURN extract(n in nodes(p) | n.name)[1]; + +START actors=node: + +MATCH (alice)-[:`REALLY LIKES`]->(bob) +MATCH (alice)-[:`REALLY ``LIKES```]->(bob) +myFancyIdentifier.`(weird property name)` +"string\t\n\b\f\\\''\"" diff --git a/tests/examplefiles/test.gradle b/tests/examplefiles/test.gradle new file mode 100644 index 00000000..0bc834c1 --- /dev/null +++ b/tests/examplefiles/test.gradle @@ -0,0 +1,20 @@ +apply plugin: 'java' + +repositories { + mavenCentral() +} + +dependencies { + testCompile 'junit:junit:4.12' +} + +task sayHello << { + def x = SomeClass.worldString + println "Hello ${x}" +} + +private class SomeClass { + public static String getWorldString() { + return "world" + } +} diff --git a/tests/examplefiles/test.idr b/tests/examplefiles/test.idr new file mode 100644 index 00000000..fd008d31 --- /dev/null +++ b/tests/examplefiles/test.idr @@ -0,0 +1,101 @@ +module Main + +data Ty = TyInt | TyBool | TyFun Ty Ty + +interpTy : Ty -> Type +interpTy TyInt = Int +interpTy TyBool = Bool +interpTy (TyFun s t) = interpTy s -> interpTy t + +using (G : Vect n Ty) + + data Env : Vect n Ty -> Type where + Nil : Env Nil + (::) : interpTy a -> Env G -> Env (a :: G) + + data HasType : (i : Fin n) -> Vect n Ty -> Ty -> Type where + stop : HasType fZ (t :: G) t + pop : HasType k G t -> HasType (fS k) (u :: G) t + + lookup : HasType i G t -> Env G -> interpTy t + lookup stop (x :: xs) = x + lookup (pop k) (x :: xs) = lookup k xs + + data Expr : Vect n Ty -> Ty -> Type where + Var : HasType i G t -> Expr G t + Val : (x : Int) -> Expr G TyInt + Lam : Expr (a :: G) t -> Expr G (TyFun a t) + App : Expr G (TyFun a t) -> Expr G a -> Expr G t + Op : (interpTy a -> interpTy b -> interpTy c) -> Expr G a -> Expr G b -> + Expr G c + If : Expr G TyBool -> Expr G a -> Expr G a -> Expr G a + Bind : Expr G a -> (interpTy a -> Expr G b) -> Expr G b + + dsl expr + lambda = Lam + variable = Var + index_first = stop + index_next = pop + + (<$>) : |(f : Expr G (TyFun a t)) -> Expr G a -> Expr G t + (<$>) = \f, a => App f a + + pure : Expr G a -> Expr G a + pure = id + + syntax IF [x] THEN [t] ELSE [e] = If x t e + + (==) : Expr G TyInt -> Expr G TyInt -> Expr G TyBool + (==) = Op (==) + + (<) : Expr G TyInt -> Expr G TyInt -> Expr G TyBool + (<) = Op (<) + + instance Num (Expr G TyInt) where + (+) x y = Op (+) x y + (-) x y = Op (-) x y + (*) x y = Op (*) x y + + abs x = IF (x < 0) THEN (-x) ELSE x + + fromInteger = Val . fromInteger + + ||| Evaluates an expression in the given context. + interp : Env G -> {static} Expr G t -> interpTy t + interp env (Var i) = lookup i env + interp env (Val x) = x + interp env (Lam sc) = \x => interp (x :: env) sc + interp env (App f s) = (interp env f) (interp env s) + interp env (Op op x y) = op (interp env x) (interp env y) + interp env (If x t e) = if (interp env x) then (interp env t) else (interp env e) + interp env (Bind v f) = interp env (f (interp env v)) + + eId : Expr G (TyFun TyInt TyInt) + eId = expr (\x => x) + + eTEST : Expr G (TyFun TyInt (TyFun TyInt TyInt)) + eTEST = expr (\x, y => y) + + eAdd : Expr G (TyFun TyInt (TyFun TyInt TyInt)) + eAdd = expr (\x, y => Op (+) x y) + + eDouble : Expr G (TyFun TyInt TyInt) + eDouble = expr (\x => App (App eAdd x) (Var stop)) + + eFac : Expr G (TyFun TyInt TyInt) + eFac = expr (\x => IF x == 0 THEN 1 ELSE [| eFac (x - 1) |] * x) + +testFac : Int +testFac = interp [] eFac 4 + +--testFacTooBig : Int +--testFacTooBig = interp [] eFac 100000 + + {-testFacTooBig2 : Int +testFacTooBig2 = interp [] eFac 1000 +-} + +main : IO () +main = print testFac + + diff --git a/tests/examplefiles/test.lean b/tests/examplefiles/test.lean new file mode 100644 index 00000000..a7b7e261 --- /dev/null +++ b/tests/examplefiles/test.lean @@ -0,0 +1,217 @@ +/- +Theorems/Exercises from "Logical Investigations, with the Nuprl Proof Assistant" +by Robert L. Constable and Anne Trostle +http://www.nuprl.org/MathLibrary/LogicalInvestigations/ +-/ +import logic + +-- 2. The Minimal Implicational Calculus +theorem thm1 {A B : Prop} : A → B → A := +assume Ha Hb, Ha + +theorem thm2 {A B C : Prop} : (A → B) → (A → B → C) → (A → C) := +assume Hab Habc Ha, + Habc Ha (Hab Ha) + +theorem thm3 {A B C : Prop} : (A → B) → (B → C) → (A → C) := +assume Hab Hbc Ha, + Hbc (Hab Ha) + +-- 3. False Propositions and Negation +theorem thm4 {P Q : Prop} : ¬P → P → Q := +assume Hnp Hp, + absurd Hp Hnp + +theorem thm5 {P : Prop} : P → ¬¬P := +assume (Hp : P) (HnP : ¬P), + absurd Hp HnP + +theorem thm6 {P Q : Prop} : (P → Q) → (¬Q → ¬P) := +assume (Hpq : P → Q) (Hnq : ¬Q) (Hp : P), + have Hq : Q, from Hpq Hp, + show false, from absurd Hq Hnq + +theorem thm7 {P Q : Prop} : (P → ¬P) → (P → Q) := +assume Hpnp Hp, + absurd Hp (Hpnp Hp) + +theorem thm8 {P Q : Prop} : ¬(P → Q) → (P → ¬Q) := +assume (Hn : ¬(P → Q)) (Hp : P) (Hq : Q), + -- Rermak we don't even need the hypothesis Hp + have H : P → Q, from assume H', Hq, + absurd H Hn + +-- 4. Conjunction and Disjunction +theorem thm9 {P : Prop} : (P ∨ ¬P) → (¬¬P → P) := +assume (em : P ∨ ¬P) (Hnn : ¬¬P), + or_elim em + (assume Hp, Hp) + (assume Hn, absurd Hn Hnn) + +theorem thm10 {P : Prop} : ¬¬(P ∨ ¬P) := +assume Hnem : ¬(P ∨ ¬P), + have Hnp : ¬P, from + assume Hp : P, + have Hem : P ∨ ¬P, from or_inl Hp, + absurd Hem Hnem, + have Hem : P ∨ ¬P, from or_inr Hnp, + absurd Hem Hnem + +theorem thm11 {P Q : Prop} : ¬P ∨ ¬Q → ¬(P ∧ Q) := +assume (H : ¬P ∨ ¬Q) (Hn : P ∧ Q), + or_elim H + (assume Hnp : ¬P, absurd (and_elim_left Hn) Hnp) + (assume Hnq : ¬Q, absurd (and_elim_right Hn) Hnq) + +theorem thm12 {P Q : Prop} : ¬(P ∨ Q) → ¬P ∧ ¬Q := +assume H : ¬(P ∨ Q), + have Hnp : ¬P, from assume Hp : P, absurd (or_inl Hp) H, + have Hnq : ¬Q, from assume Hq : Q, absurd (or_inr Hq) H, + and_intro Hnp Hnq + +theorem thm13 {P Q : Prop} : ¬P ∧ ¬Q → ¬(P ∨ Q) := +assume (H : ¬P ∧ ¬Q) (Hn : P ∨ Q), + or_elim Hn + (assume Hp : P, absurd Hp (and_elim_left H)) + (assume Hq : Q, absurd Hq (and_elim_right H)) + +theorem thm14 {P Q : Prop} : ¬P ∨ Q → P → Q := +assume (Hor : ¬P ∨ Q) (Hp : P), + or_elim Hor + (assume Hnp : ¬P, absurd Hp Hnp) + (assume Hq : Q, Hq) + +theorem thm15 {P Q : Prop} : (P → Q) → ¬¬(¬P ∨ Q) := +assume (Hpq : P → Q) (Hn : ¬(¬P ∨ Q)), + have H1 : ¬¬P ∧ ¬Q, from thm12 Hn, + have Hnp : ¬P, from mt Hpq (and_elim_right H1), + absurd Hnp (and_elim_left H1) + +theorem thm16 {P Q : Prop} : (P → Q) ∧ ((P ∨ ¬P) ∨ (Q ∨ ¬Q)) → ¬P ∨ Q := +assume H : (P → Q) ∧ ((P ∨ ¬P) ∨ (Q ∨ ¬Q)), + have Hpq : P → Q, from and_elim_left H, + or_elim (and_elim_right H) + (assume Hem1 : P ∨ ¬P, or_elim Hem1 + (assume Hp : P, or_inr (Hpq Hp)) + (assume Hnp : ¬P, or_inl Hnp)) + (assume Hem2 : Q ∨ ¬Q, or_elim Hem2 + (assume Hq : Q, or_inr Hq) + (assume Hnq : ¬Q, or_inl (mt Hpq Hnq))) + +-- 5. First-Order Logic: All and Exists +section +parameters {T : Type} {C : Prop} {P : T → Prop} +theorem thm17a : (C → ∀x, P x) → (∀x, C → P x) := +assume H : C → ∀x, P x, + take x : T, assume Hc : C, + H Hc x + +theorem thm17b : (∀x, C → P x) → (C → ∀x, P x) := +assume (H : ∀x, C → P x) (Hc : C), + take x : T, + H x Hc + +theorem thm18a : ((∃x, P x) → C) → (∀x, P x → C) := +assume H : (∃x, P x) → C, + take x, assume Hp : P x, + have Hex : ∃x, P x, from exists_intro x Hp, + H Hex + +theorem thm18b : (∀x, P x → C) → (∃x, P x) → C := +assume (H1 : ∀x, P x → C) (H2 : ∃x, P x), + obtain (w : T) (Hw : P w), from H2, + H1 w Hw + +theorem thm19a : (C ∨ ¬C) → (∃x : T, true) → (C → (∃x, P x)) → (∃x, C → P x) := +assume (Hem : C ∨ ¬C) (Hin : ∃x : T, true) (H1 : C → ∃x, P x), + or_elim Hem + (assume Hc : C, + obtain (w : T) (Hw : P w), from H1 Hc, + have Hr : C → P w, from assume Hc, Hw, + exists_intro w Hr) + (assume Hnc : ¬C, + obtain (w : T) (Hw : true), from Hin, + have Hr : C → P w, from assume Hc, absurd Hc Hnc, + exists_intro w Hr) + +theorem thm19b : (∃x, C → P x) → C → (∃x, P x) := +assume (H : ∃x, C → P x) (Hc : C), + obtain (w : T) (Hw : C → P w), from H, + exists_intro w (Hw Hc) + +theorem thm20a : (C ∨ ¬C) → (∃x : T, true) → ((¬∀x, P x) → ∃x, ¬P x) → ((∀x, P x) → C) → (∃x, P x → C) := +assume Hem Hin Hnf H, + or_elim Hem + (assume Hc : C, + obtain (w : T) (Hw : true), from Hin, + exists_intro w (assume H : P w, Hc)) + (assume Hnc : ¬C, + have H1 : ¬(∀x, P x), from mt H Hnc, + have H2 : ∃x, ¬P x, from Hnf H1, + obtain (w : T) (Hw : ¬P w), from H2, + exists_intro w (assume H : P w, absurd H Hw)) + +theorem thm20b : (∃x, P x → C) → (∀ x, P x) → C := +assume Hex Hall, + obtain (w : T) (Hw : P w → C), from Hex, + Hw (Hall w) + +theorem thm21a : (∃x : T, true) → ((∃x, P x) ∨ C) → (∃x, P x ∨ C) := +assume Hin H, + or_elim H + (assume Hex : ∃x, P x, + obtain (w : T) (Hw : P w), from Hex, + exists_intro w (or_inl Hw)) + (assume Hc : C, + obtain (w : T) (Hw : true), from Hin, + exists_intro w (or_inr Hc)) + +theorem thm21b : (∃x, P x ∨ C) → ((∃x, P x) ∨ C) := +assume H, + obtain (w : T) (Hw : P w ∨ C), from H, + or_elim Hw + (assume H : P w, or_inl (exists_intro w H)) + (assume Hc : C, or_inr Hc) + +theorem thm22a : (∀x, P x) ∨ C → ∀x, P x ∨ C := +assume H, take x, + or_elim H + (assume Hl, or_inl (Hl x)) + (assume Hr, or_inr Hr) + +theorem thm22b : (C ∨ ¬C) → (∀x, P x ∨ C) → ((∀x, P x) ∨ C) := +assume Hem H1, + or_elim Hem + (assume Hc : C, or_inr Hc) + (assume Hnc : ¬C, + have Hx : ∀x, P x, from + take x, + have H1 : P x ∨ C, from H1 x, + resolve_left H1 Hnc, + or_inl Hx) + +theorem thm23a : (∃x, P x) ∧ C → (∃x, P x ∧ C) := +assume H, + have Hex : ∃x, P x, from and_elim_left H, + have Hc : C, from and_elim_right H, + obtain (w : T) (Hw : P w), from Hex, + exists_intro w (and_intro Hw Hc) + +theorem thm23b : (∃x, P x ∧ C) → (∃x, P x) ∧ C := +assume H, + obtain (w : T) (Hw : P w ∧ C), from H, + have Hex : ∃x, P x, from exists_intro w (and_elim_left Hw), + and_intro Hex (and_elim_right Hw) + +theorem thm24a : (∀x, P x) ∧ C → (∀x, P x ∧ C) := +assume H, take x, + and_intro (and_elim_left H x) (and_elim_right H) + +theorem thm24b : (∃x : T, true) → (∀x, P x ∧ C) → (∀x, P x) ∧ C := +assume Hin H, + obtain (w : T) (Hw : true), from Hin, + have Hc : C, from and_elim_right (H w), + have Hx : ∀x, P x, from take x, and_elim_left (H x), + and_intro Hx Hc + +end -- of section diff --git a/tests/examplefiles/test.mask b/tests/examplefiles/test.mask new file mode 100644 index 00000000..39134d74 --- /dev/null +++ b/tests/examplefiles/test.mask @@ -0,0 +1,41 @@ +
+// comment
+h4.class-1#id.class-2.other checked='true' disabled name = x param > 'Enter ..'
+input placeholder=Password type=password >
+ :dualbind x-signal='dom:create' value=user.passord;
+% each='flowers' >
+ div style='
+ position: absolute;
+ display: inline-block;
+ background: url("image.png") center center no-repeat;
+ ';
+#skippedDiv.other {
+ img src='~[url]';
+ div style="text-align:center;" {
+ '~[: $obj.foo("username", name) + 2]'
+ "~[Localize: stringId]"
+ }
+
+ p > """
+
+ Hello "world"
+ """
+
+ p > '
+ Hello "world"
+ '
+
+ p > "Hello 'world'"
+
+ :customComponent x-value='tt';
+ /* footer > '(c) 2014' */
+}
+
+.skippedDiv >
+ span >
+ #skipped >
+ table >
+ td >
+ tr > ';)'
+
+br;
\ No newline at end of file diff --git a/tests/examplefiles/test.pan b/tests/examplefiles/test.pan new file mode 100644 index 00000000..56c8bd62 --- /dev/null +++ b/tests/examplefiles/test.pan @@ -0,0 +1,54 @@ +object template pantest; + +# Very simple pan test file +"/long/decimal" = 123; +"/long/octal" = 0755; +"/long/hexadecimal" = 0xFF; + +"/double/simple" = 0.01; +"/double/pi" = 3.14159; +"/double/exponent" = 1e-8; +"/double/scientific" = 1.3E10; + +"/string/single" = 'Faster, but escapes like \t, \n and \x3d don''t work, but '' should work.'; +"/string/double" = "Slower, but escapes like \t, \n and \x3d do work"; + +variable TEST = 2; + +"/x2" = to_string(TEST); +"/x2" ?= 'Default value'; + +"/x3" = 1 + 2 + value("/long/decimal"); + +"/x4" = undef; + +"/x5" = null; + +variable e ?= error("Test error message"); + +# include gmond config for services-monitoring +include { 'site/ganglia/gmond/services-monitoring' }; + +"/software/packages"=pkg_repl("httpd","2.2.3-43.sl5.3",PKG_ARCH_DEFAULT); +"/software/packages"=pkg_repl("php"); + +# Example function +function show_things_view_for_stuff = { + thing = ARGV[0]; + foreach( i; mything; STUFF ) { + if ( thing == mything ) { + return( true ); + } else { + return SELF; + }; + }; + false; +}; + +variable HERE = <<EOF; +; This example demonstrates an in-line heredoc style config file +[main] +awesome = true +EOF + +variable small = false;#This should be highlighted normally again. diff --git a/tests/examplefiles/test.php b/tests/examplefiles/test.php index 97e21f73..2ce4023e 100644 --- a/tests/examplefiles/test.php +++ b/tests/examplefiles/test.php @@ -1,5 +1,7 @@ <?php +$disapproval_ಠ_ಠ_of_php = 'unicode var'; + $test = function($a) { $lambda = 1; } /** @@ -16,7 +18,7 @@ if(!defined('UNLOCK') || !UNLOCK) // Load the parent archive class require_once(ROOT_PATH.'/classes/archive.class.php'); -class Zip\Zipp { +class Zip\Zippಠ_ಠ_ { } @@ -502,4 +504,12 @@ function &byref() { $x = array(); return $x; } + + echo <<<EOF + + Test the heredocs... + + EOF; + ?> + diff --git a/tests/examplefiles/test.pig b/tests/examplefiles/test.pig new file mode 100644 index 00000000..f67b0268 --- /dev/null +++ b/tests/examplefiles/test.pig @@ -0,0 +1,148 @@ +/** + * This script is an example recommender (using made up data) showing how you might modify item-item links + * by defining similar relations between items in a dataset and customizing the change in weighting. + * This example creates metadata by using the genre field as the metadata_field. The items with + * the same genre have it's weight cut in half in order to boost the signals of movies that do not have the same genre. + * This technique requires a customization of the standard GetItemItemRecommendations macro + */ +import 'recommenders.pig'; + + + +%default INPUT_PATH_PURCHASES '../data/retail/purchases.json' +%default INPUT_PATH_WISHLIST '../data/retail/wishlists.json' +%default INPUT_PATH_INVENTORY '../data/retail/inventory.json' +%default OUTPUT_PATH '../data/retail/out/modify_item_item' + + +/******** Custom GetItemItemRecommnedations *********/ +define recsys__GetItemItemRecommendations_ModifyCustom(user_item_signals, metadata) returns item_item_recs { + + -- Convert user_item_signals to an item_item_graph + ii_links_raw, item_weights = recsys__BuildItemItemGraph( + $user_item_signals, + $LOGISTIC_PARAM, + $MIN_LINK_WEIGHT, + $MAX_LINKS_PER_USER + ); + -- NOTE this function is added in order to combine metadata with item-item links + -- See macro for more detailed explination + ii_links_metadata = recsys__AddMetadataToItemItemLinks( + ii_links_raw, + $metadata + ); + + /********* Custom Code starts here ********/ + + --The code here should adjust the weights based on an item-item link and the equality of metadata. + -- In this case, if the metadata is the same, the weight is reduced. Otherwise the weight is left alone. + ii_links_adjusted = foreach ii_links_metadata generate item_A, item_B, + -- the amount of weight adjusted is dependant on the domain of data and what is expected + -- It is always best to adjust the weight by multiplying it by a factor rather than addition with a constant + (metadata_B == metadata_A ? (weight * 0.5): weight) as weight; + + + /******** Custom Code stops here *********/ + + -- remove negative numbers just incase + ii_links_adjusted_filt = foreach ii_links_adjusted generate item_A, item_B, + (weight <= 0 ? 0: weight) as weight; + -- Adjust the weights of the graph to improve recommendations. + ii_links = recsys__AdjustItemItemGraphWeight( + ii_links_adjusted_filt, + item_weights, + $BAYESIAN_PRIOR + ); + + -- Use the item-item graph to create item-item recommendations. + $item_item_recs = recsys__BuildItemItemRecommendationsFromGraph( + ii_links, + $NUM_RECS_PER_ITEM, + $NUM_RECS_PER_ITEM + ); +}; + + +/******* Load Data **********/ + +--Get purchase signals +purchase_input = load '$INPUT_PATH_PURCHASES' using org.apache.pig.piggybank.storage.JsonLoader( + 'row_id: int, + movie_id: chararray, + movie_name: chararray, + user_id: chararray, + purchase_price: int'); + +--Get wishlist signals +wishlist_input = load '$INPUT_PATH_WISHLIST' using org.apache.pig.piggybank.storage.JsonLoader( + 'row_id: int, + movie_id: chararray, + movie_name: chararray, + user_id: chararray'); + + +/******* Convert Data to Signals **********/ + +-- Start with choosing 1 as max weight for a signal. +purchase_signals = foreach purchase_input generate + user_id as user, + movie_name as item, + 1.0 as weight; + + +-- Start with choosing 0.5 as weight for wishlist items because that is a weaker signal than +-- purchasing an item. +wishlist_signals = foreach wishlist_input generate + user_id as user, + movie_name as item, + 0.5 as weight; + +user_signals = union purchase_signals, wishlist_signals; + + +/******** Changes for Modifying item-item links ******/ +inventory_input = load '$INPUT_PATH_INVENTORY' using org.apache.pig.piggybank.storage.JsonLoader( + 'movie_title: chararray, + genres: bag{tuple(content:chararray)}'); + + +metadata = foreach inventory_input generate + FLATTEN(genres) as metadata_field, + movie_title as item; +-- requires the macro to be written seperately + --NOTE this macro is defined within this file for clarity +item_item_recs = recsys__GetItemItemRecommendations_ModifyCustom(user_signals, metadata); +/******* No more changes ********/ + + +user_item_recs = recsys__GetUserItemRecommendations(user_signals, item_item_recs); + +--Completely unrelated code stuck in the middle +data = LOAD 's3n://my-s3-bucket/path/to/responses' + USING org.apache.pig.piggybank.storage.JsonLoader(); +responses = FOREACH data GENERATE object#'response' AS response: map[]; +out = FOREACH responses + GENERATE response#'id' AS id: int, response#'thread' AS thread: chararray, + response#'comments' AS comments: {t: (comment: chararray)}; +STORE out INTO 's3n://path/to/output' USING PigStorage('|'); + + +/******* Store recommendations **********/ + +-- If your output folder exists already, hadoop will refuse to write data to it. + +rmf $OUTPUT_PATH/item_item_recs; +rmf $OUTPUT_PATH/user_item_recs; + +store item_item_recs into '$OUTPUT_PATH/item_item_recs' using PigStorage(); +store user_item_recs into '$OUTPUT_PATH/user_item_recs' using PigStorage(); + +-- STORE the item_item_recs into dynamo +STORE item_item_recs + INTO '$OUTPUT_PATH/unused-ii-table-data' +USING com.mortardata.pig.storage.DynamoDBStorage('$II_TABLE', '$AWS_ACCESS_KEY_ID', '$AWS_SECRET_ACCESS_KEY'); + +-- STORE the user_item_recs into dynamo +STORE user_item_recs + INTO '$OUTPUT_PATH/unused-ui-table-data' +USING com.mortardata.pig.storage.DynamoDBStorage('$UI_TABLE', '$AWS_ACCESS_KEY_ID', '$AWS_SECRET_ACCESS_KEY'); diff --git a/tests/examplefiles/test.pwn b/tests/examplefiles/test.pwn new file mode 100644 index 00000000..d6468617 --- /dev/null +++ b/tests/examplefiles/test.pwn @@ -0,0 +1,253 @@ +#include <core> + +// Single line comment +/* Multi line + comment */ + +/// documentation +/** + + documentation multi line + +**/ + +public OnGameModeInit() { + printf("Hello, World!"); +} + +enum info { + Float:ex; + exa, + exam[5], +} +new arr[5][info]; + +stock Float:test_func() +{ + new a = 5, Float:b = 10.3; + if (a == b) { + + } else { + + } + + for (new i = 0; i < 10; i++) { + continue; + } + + do { + a--; + } while (a > 0); + + while (a < 5) { + a++; + break; + } + + switch (a) { + case 0: { + } + case 0..4: { + } + case 5, 6: { + } + } + + static x; + new xx = a > 5 ? 5 : 0; + new array[sizeof arr] = {0}; + tagof a; + state a; + goto label; + new byte[2 char]; + byte{0} = 'a'; + + return (float(a) + b); +} + + +// float.inc +/* Float arithmetic + * + * (c) Copyright 1999, Artran, Inc. + * Written by Greg Garner (gmg@artran.com) + * Modified in March 2001 to include user defined + * operators for the floating point functions. + * + * This file is provided as is (no warranties). + */ +#if defined _Float_included + #endinput +#endif +#define _Float_included +#pragma library Float + +/* Different methods of rounding */ +enum floatround_method { + floatround_round, + floatround_floor, + floatround_ceil, + floatround_tozero, + floatround_unbiased +} +enum anglemode { + radian, + degrees, + grades +} + +/**************************************************/ +/* Convert an integer into a floating point value */ +native Float:float(value); + +/**************************************************/ +/* Convert a string into a floating point value */ +native Float:floatstr(const string[]); + +/**************************************************/ +/* Multiple two floats together */ +native Float:floatmul(Float:oper1, Float:oper2); + +/**************************************************/ +/* Divide the dividend float by the divisor float */ +native Float:floatdiv(Float:dividend, Float:divisor); + +/**************************************************/ +/* Add two floats together */ +native Float:floatadd(Float:oper1, Float:oper2); + +/**************************************************/ +/* Subtract oper2 float from oper1 float */ +native Float:floatsub(Float:oper1, Float:oper2); + +/**************************************************/ +/* Return the fractional part of a float */ +native Float:floatfract(Float:value); + +/**************************************************/ +/* Round a float into a integer value */ +native floatround(Float:value, floatround_method:method=floatround_round); + +/**************************************************/ +/* Compare two integers. If the two elements are equal, return 0. + If the first argument is greater than the second argument, return 1, + If the first argument is less than the second argument, return -1. */ +native floatcmp(Float:oper1, Float:oper2); + +/**************************************************/ +/* Return the square root of the input value, same as floatpower(value, 0.5) */ +native Float:floatsqroot(Float:value); + +/**************************************************/ +/* Return the value raised to the power of the exponent */ +native Float:floatpower(Float:value, Float:exponent); + +/**************************************************/ +/* Return the logarithm */ +native Float:floatlog(Float:value, Float:base=10.0); + +/**************************************************/ +/* Return the sine, cosine or tangent. The input angle may be in radian, + degrees or grades. */ +native Float:floatsin(Float:value, anglemode:mode=radian); +native Float:floatcos(Float:value, anglemode:mode=radian); +native Float:floattan(Float:value, anglemode:mode=radian); + +/**************************************************/ +/* Return the absolute value */ +native Float:floatabs(Float:value); + + +/**************************************************/ +#pragma rational Float + +/* user defined operators */ +native Float:operator*(Float:oper1, Float:oper2) = floatmul; +native Float:operator/(Float:oper1, Float:oper2) = floatdiv; +native Float:operator+(Float:oper1, Float:oper2) = floatadd; +native Float:operator-(Float:oper1, Float:oper2) = floatsub; +native Float:operator=(oper) = float; + +stock Float:operator++(Float:oper) + return oper+1.0; + +stock Float:operator--(Float:oper) + return oper-1.0; + +stock Float:operator-(Float:oper) + return oper^Float:cellmin; /* IEEE values are sign/magnitude */ + +stock Float:operator*(Float:oper1, oper2) + return floatmul(oper1, float(oper2)); /* "*" is commutative */ + +stock Float:operator/(Float:oper1, oper2) + return floatdiv(oper1, float(oper2)); + +stock Float:operator/(oper1, Float:oper2) + return floatdiv(float(oper1), oper2); + +stock Float:operator+(Float:oper1, oper2) + return floatadd(oper1, float(oper2)); /* "+" is commutative */ + +stock Float:operator-(Float:oper1, oper2) + return floatsub(oper1, float(oper2)); + +stock Float:operator-(oper1, Float:oper2) + return floatsub(float(oper1), oper2); + +stock bool:operator==(Float:oper1, Float:oper2) + return floatcmp(oper1, oper2) == 0; + +stock bool:operator==(Float:oper1, oper2) + return floatcmp(oper1, float(oper2)) == 0; /* "==" is commutative */ + +stock bool:operator!=(Float:oper1, Float:oper2) + return floatcmp(oper1, oper2) != 0; + +stock bool:operator!=(Float:oper1, oper2) + return floatcmp(oper1, float(oper2)) != 0; /* "!=" is commutative */ + +stock bool:operator>(Float:oper1, Float:oper2) + return floatcmp(oper1, oper2) > 0; + +stock bool:operator>(Float:oper1, oper2) + return floatcmp(oper1, float(oper2)) > 0; + +stock bool:operator>(oper1, Float:oper2) + return floatcmp(float(oper1), oper2) > 0; + +stock bool:operator>=(Float:oper1, Float:oper2) + return floatcmp(oper1, oper2) >= 0; + +stock bool:operator>=(Float:oper1, oper2) + return floatcmp(oper1, float(oper2)) >= 0; + +stock bool:operator>=(oper1, Float:oper2) + return floatcmp(float(oper1), oper2) >= 0; + +stock bool:operator<(Float:oper1, Float:oper2) + return floatcmp(oper1, oper2) < 0; + +stock bool:operator<(Float:oper1, oper2) + return floatcmp(oper1, float(oper2)) < 0; + +stock bool:operator<(oper1, Float:oper2) + return floatcmp(float(oper1), oper2) < 0; + +stock bool:operator<=(Float:oper1, Float:oper2) + return floatcmp(oper1, oper2) <= 0; + +stock bool:operator<=(Float:oper1, oper2) + return floatcmp(oper1, float(oper2)) <= 0; + +stock bool:operator<=(oper1, Float:oper2) + return floatcmp(float(oper1), oper2) <= 0; + +stock bool:operator!(Float:oper) + return (_:oper & cellmax) == 0; + +/* forbidden operations */ +forward operator%(Float:oper1, Float:oper2); +forward operator%(Float:oper1, oper2); +forward operator%(oper1, Float:oper2); + diff --git a/tests/examplefiles/test.pypylog b/tests/examplefiles/test.pypylog index f85030cb..1a6aa5ed 100644 --- a/tests/examplefiles/test.pypylog +++ b/tests/examplefiles/test.pypylog @@ -998,842 +998,3 @@ setfield_gc(p73, i14, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntO setarrayitem_gc(p60, 9, p73, descr=<GcPtrArrayDescr>) p76 = new_with_vtable(19800744) setfield_gc(p76, f15, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -setarrayitem_gc(p60, 10, p76, descr=<GcPtrArrayDescr>) -setfield_gc(p1, 1, descr=<BoolFieldDescr pypy.interpreter.pyframe.PyFrame.inst_frame_finished_execution 148>) -setfield_gc(p1, ConstPtr(ptr79), descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_pycode 112>) -setfield_gc(p1, ConstPtr(ptr55), descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_lastblock 104>) -setfield_gc(p1, 0, descr=<SignedFieldDescr pypy.interpreter.pyframe.PyFrame.inst_valuestackdepth 128>) -setfield_gc(p1, p4, descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_last_exception 88>) -setfield_gc(p1, 0, descr=<BoolFieldDescr pypy.interpreter.pyframe.PyFrame.inst_is_being_profiled 149>) -setfield_gc(p1, 307, descr=<SignedFieldDescr pypy.interpreter.pyframe.PyFrame.inst_last_instr 96>) -p84 = new_with_vtable(19800744) -setfield_gc(p84, f36, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -finish(p84, descr=<DoneWithThisFrameDescrRef object at 0x140bcc0>) -[5ed6619e9448] jit-log-opt-bridge} -[5ed74f2eef6e] {jit-log-opt-loop -# Loop 2 : loop with 394 ops -[p0, p1, p2, p3, p4, p5, p6, p7, i8, f9, i10, i11, p12, p13] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #21 LOAD_FAST', 0) -guard_nonnull_class(p7, 19800744, descr=<Guard180>) [p1, p0, p7, p2, p3, p4, p5, p6, i8] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #24 LOAD_FAST', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #27 COMPARE_OP', 0) -f15 = getfield_gc_pure(p7, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -i16 = float_gt(f15, f9) -guard_true(i16, descr=<Guard181>) [p1, p0, p6, p7, p2, p3, p4, p5, i8] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #30 POP_JUMP_IF_FALSE', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #33 LOAD_FAST', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #36 POP_JUMP_IF_FALSE', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #39 LOAD_FAST', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #42 LOAD_FAST', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #45 COMPARE_OP', 0) -i17 = int_ge(i8, i10) -guard_false(i17, descr=<Guard182>) [p1, p0, p5, p2, p3, p4, p6, p7, i8] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #48 POP_JUMP_IF_FALSE', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #55 LOAD_GLOBAL', 0) -p18 = getfield_gc(p0, descr=<GcPtrFieldDescr pypy.interpreter.eval.Frame.inst_w_globals 8>) -guard_value(p18, ConstPtr(ptr19), descr=<Guard183>) [p1, p0, p18, p2, p3, p4, p5, p6, p7, i8] -p20 = getfield_gc(p18, descr=<GcPtrFieldDescr pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_r_dict_content 8>) -guard_isnull(p20, descr=<Guard184>) [p1, p0, p20, p18, p2, p3, p4, p5, p6, p7, i8] -p22 = getfield_gc(ConstPtr(ptr21), descr=<GcPtrFieldDescr pypy.objspace.std.celldict.ModuleCell.inst_w_value 8>) -guard_nonnull_class(p22, ConstClass(Function), descr=<Guard185>) [p1, p0, p22, p2, p3, p4, p5, p6, p7, i8] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #58 LOAD_FAST', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #61 CALL_FUNCTION', 0) -p24 = getfield_gc(p22, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_code 24>) -guard_value(p24, ConstPtr(ptr25), descr=<Guard186>) [p1, p0, p24, p22, p2, p3, p4, p5, p6, p7, i8] -p26 = getfield_gc(p22, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_w_func_globals 64>) -p27 = getfield_gc(p22, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_closure 16>) -i28 = force_token() -i29 = int_is_zero(i11) -guard_true(i29, descr=<Guard187>) [p1, p0, p12, p2, p3, p22, p4, p5, p6, p7, p26, p13, i28, i8] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #0 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #3 LOAD_ATTR', 1) -p30 = getfield_gc(p4, descr=<GcPtrFieldDescr pypy.objspace.std.mapdict.W_ObjectObjectSize5.inst_map 48>) -guard_value(p30, ConstPtr(ptr31), descr=<Guard188>) [p1, p0, p12, p4, p30, p2, p3, p22, p5, p6, p7, p26, p13, i28, i8] -p33 = getfield_gc(ConstPtr(ptr32), descr=<GcPtrFieldDescr pypy.objspace.std.typeobject.W_TypeObject.inst__version_tag 16>) -guard_value(p33, ConstPtr(ptr34), descr=<Guard189>) [p1, p0, p12, p4, p33, p2, p3, p22, p5, p6, p7, p26, p13, i28, i8] -p35 = getfield_gc(p4, descr=<GcPtrFieldDescr pypy.objspace.std.mapdict.W_ObjectObjectSize5.inst__value2 24>) -guard_nonnull_class(p35, 19800744, descr=<Guard190>) [p1, p0, p12, p35, p4, p2, p3, p22, p5, p6, p7, p26, p13, i28, i8] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #6 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #9 LOAD_ATTR', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #12 BINARY_MULTIPLY', 1) -f37 = getfield_gc_pure(p35, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -f38 = float_mul(f37, f37) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #13 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #16 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #19 LOAD_ATTR', 1) -p39 = getfield_gc(p4, descr=<GcPtrFieldDescr pypy.objspace.std.mapdict.W_ObjectObjectSize5.inst__value3 32>) -guard_nonnull_class(p39, 19800744, descr=<Guard191>) [p1, p0, p12, p39, p4, p2, p3, p22, p5, p6, p7, f38, p26, p13, i28, i8] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #22 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #25 LOAD_ATTR', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #28 BINARY_MULTIPLY', 1) -f41 = getfield_gc_pure(p39, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -f42 = float_mul(f41, f41) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #29 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #32 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #35 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #38 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #41 BINARY_ADD', 1) -f43 = float_add(f38, f42) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #42 BINARY_DIVIDE', 1) -i45 = float_eq(f43, 0.000000) -guard_false(i45, descr=<Guard192>) [p1, p0, p12, f43, p2, p3, p22, p4, p5, p6, p7, f42, f38, p26, p13, i28, i8] -f47 = float_truediv(0.500000, f43) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #43 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #46 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #49 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #52 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #55 LOAD_ATTR', 1) -p48 = getfield_gc(p4, descr=<GcPtrFieldDescr pypy.objspace.std.mapdict.W_ObjectObjectSize5.inst__value0 8>) -guard_nonnull_class(p48, ConstClass(W_IntObject), descr=<Guard193>) [p1, p0, p12, p48, p4, p2, p3, p22, p5, p6, p7, f47, f42, f38, p26, p13, i28, i8] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #58 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #61 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #64 LOAD_ATTR', 1) -p50 = getfield_gc(p4, descr=<GcPtrFieldDescr pypy.objspace.std.mapdict.W_ObjectObjectSize5.inst__value1 16>) -guard_nonnull_class(p50, ConstClass(W_IntObject), descr=<Guard194>) [p1, p0, p12, p50, p4, p2, p3, p22, p5, p6, p7, p48, f47, f42, f38, p26, p13, i28, i8] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #67 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #70 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #73 LOAD_ATTR', 1) -p52 = getfield_gc(p4, descr=<GcPtrFieldDescr pypy.objspace.std.mapdict.W_ObjectObjectSize5.inst__value4 40>) -guard_nonnull_class(p52, 19886912, descr=<Guard195>) [p1, p0, p12, p52, p4, p2, p3, p22, p5, p6, p7, p50, p48, f47, f42, f38, p26, p13, i28, i8] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #76 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #79 SETUP_LOOP', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #82 LOAD_GLOBAL', 1) -guard_value(p26, ConstPtr(ptr54), descr=<Guard196>) [p1, p0, p12, p26, p2, p3, p22, p4, p5, p6, p7, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -p56 = getfield_gc(p26, descr=<GcPtrFieldDescr pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_r_dict_content 8>) -guard_isnull(p56, descr=<Guard197>) [p1, p0, p12, p56, p26, p2, p3, p22, p4, p5, p6, p7, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -p58 = getfield_gc(ConstPtr(ptr57), descr=<GcPtrFieldDescr pypy.objspace.std.celldict.ModuleCell.inst_w_value 8>) -guard_isnull(p58, descr=<Guard198>) [p1, p0, p12, p58, p2, p3, p22, p4, p5, p6, p7, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -p60 = getfield_gc(ConstPtr(ptr59), descr=<GcPtrFieldDescr pypy.interpreter.module.Module.inst_w_dict 8>) -guard_value(p60, ConstPtr(ptr61), descr=<Guard199>) [p1, p0, p12, p60, p2, p3, p22, p4, p5, p6, p7, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -p62 = getfield_gc(p60, descr=<GcPtrFieldDescr pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_r_dict_content 8>) -guard_isnull(p62, descr=<Guard200>) [p1, p0, p12, p62, p60, p2, p3, p22, p4, p5, p6, p7, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -p64 = getfield_gc(ConstPtr(ptr63), descr=<GcPtrFieldDescr pypy.objspace.std.celldict.ModuleCell.inst_w_value 8>) -guard_value(p64, ConstPtr(ptr65), descr=<Guard201>) [p1, p0, p12, p64, p2, p3, p22, p4, p5, p6, p7, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #85 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #88 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #91 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #94 BINARY_SUBTRACT', 1) -i66 = getfield_gc_pure(p48, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval 8>) -i68 = int_sub_ovf(i66, 1) -guard_no_overflow(, descr=<Guard202>) [p1, p0, p12, p48, i68, p2, p3, p22, p4, p5, p6, p7, p64, p52, p50, None, f47, f42, f38, None, p13, i28, i8] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #95 CALL_FUNCTION', 1) -p70 = getfield_gc(ConstPtr(ptr69), descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_name 40>) -p71 = getfield_gc(ConstPtr(ptr69), descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_defs 32>) -i72 = getfield_gc_pure(p71, descr=<BoolFieldDescr pypy.interpreter.function.Defaults.inst_promote 16>) -guard_false(i72, descr=<Guard203>) [p1, p0, p12, p70, p71, p2, p3, p22, p4, p5, p6, p7, i68, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -p73 = getfield_gc_pure(p71, descr=<GcPtrFieldDescr pypy.interpreter.function.Defaults.inst_items 8>) -i74 = arraylen_gc(p73, descr=<GcPtrArrayDescr>) -i76 = int_sub(4, i74) -i78 = int_ge(3, i76) -guard_true(i78, descr=<Guard204>) [p1, p0, p12, p70, i76, p71, p2, p3, p22, p4, p5, p6, p7, i68, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -i79 = int_sub(3, i76) -i80 = getfield_gc_pure(p71, descr=<BoolFieldDescr pypy.interpreter.function.Defaults.inst_promote 16>) -guard_false(i80, descr=<Guard205>) [p1, p0, p12, p70, i79, i76, p71, p2, p3, p22, p4, p5, p6, p7, i68, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -p81 = getfield_gc_pure(p71, descr=<GcPtrFieldDescr pypy.interpreter.function.Defaults.inst_items 8>) -p82 = getarrayitem_gc(p81, i79, descr=<GcPtrArrayDescr>) -guard_class(p82, ConstClass(W_IntObject), descr=<Guard206>) [p1, p0, p12, p82, p2, p3, p22, p4, p5, p6, p7, i68, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -i84 = getfield_gc_pure(p82, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval 8>) -i85 = int_is_zero(i84) -guard_false(i85, descr=<Guard207>) [p1, p0, p12, i84, i68, p2, p3, p22, p4, p5, p6, p7, p82, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -i87 = int_lt(i84, 0) -guard_false(i87, descr=<Guard208>) [p1, p0, p12, i84, i68, p2, p3, p22, p4, p5, p6, p7, p82, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -i89 = int_lt(1, i68) -guard_true(i89, descr=<Guard209>) [p1, p0, p12, i84, i68, p2, p3, p22, p4, p5, p6, p7, p82, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -i90 = int_sub(i68, 1) -i92 = int_sub(i90, 1) -i93 = uint_floordiv(i92, i84) -i95 = int_add(i93, 1) -i97 = int_lt(i95, 0) -guard_false(i97, descr=<Guard210>) [p1, p0, p12, i84, i95, p2, p3, p22, p4, p5, p6, p7, p82, i68, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #98 GET_ITER', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #99 FOR_ITER', 1) -i99 = int_gt(i95, 0) -guard_true(i99, descr=<Guard211>) [p1, p0, p12, p2, p3, p22, p4, p5, p6, p7, i84, i95, None, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -i100 = int_add(1, i84) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #102 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #105 SETUP_LOOP', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #108 LOAD_GLOBAL', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #111 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #114 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #117 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #120 BINARY_SUBTRACT', 1) -i101 = getfield_gc_pure(p50, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval 8>) -i103 = int_sub_ovf(i101, 1) -guard_no_overflow(, descr=<Guard212>) [p1, p0, p12, p50, i103, p2, p3, p22, p4, p5, p6, p7, i100, i93, i84, None, None, None, None, p52, None, p48, f47, f42, f38, None, p13, i28, i8] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #121 CALL_FUNCTION', 1) -i104 = getfield_gc_pure(p71, descr=<BoolFieldDescr pypy.interpreter.function.Defaults.inst_promote 16>) -guard_false(i104, descr=<Guard213>) [p1, p0, p12, p70, p71, p2, p3, p22, p4, p5, p6, p7, i103, i100, i93, i84, None, None, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -p105 = getfield_gc_pure(p71, descr=<GcPtrFieldDescr pypy.interpreter.function.Defaults.inst_items 8>) -i106 = arraylen_gc(p105, descr=<GcPtrArrayDescr>) -i108 = int_sub(4, i106) -i110 = int_ge(3, i108) -guard_true(i110, descr=<Guard214>) [p1, p0, p12, p70, i108, p71, p2, p3, p22, p4, p5, p6, p7, i103, i100, i93, i84, None, None, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -i111 = int_sub(3, i108) -i112 = getfield_gc_pure(p71, descr=<BoolFieldDescr pypy.interpreter.function.Defaults.inst_promote 16>) -guard_false(i112, descr=<Guard215>) [p1, p0, p12, p70, i111, i108, p71, p2, p3, p22, p4, p5, p6, p7, i103, i100, i93, i84, None, None, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -p113 = getfield_gc_pure(p71, descr=<GcPtrFieldDescr pypy.interpreter.function.Defaults.inst_items 8>) -p114 = getarrayitem_gc(p113, i111, descr=<GcPtrArrayDescr>) -guard_class(p114, ConstClass(W_IntObject), descr=<Guard216>) [p1, p0, p12, p114, p2, p3, p22, p4, p5, p6, p7, i103, i100, i93, i84, None, None, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -i116 = getfield_gc_pure(p114, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval 8>) -i117 = int_is_zero(i116) -guard_false(i117, descr=<Guard217>) [p1, p0, p12, i116, i103, p2, p3, p22, p4, p5, p6, p7, p114, None, i100, i93, i84, None, None, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -i119 = int_lt(i116, 0) -guard_false(i119, descr=<Guard218>) [p1, p0, p12, i116, i103, p2, p3, p22, p4, p5, p6, p7, p114, None, i100, i93, i84, None, None, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -i121 = int_lt(1, i103) -guard_true(i121, descr=<Guard219>) [p1, p0, p12, i116, i103, p2, p3, p22, p4, p5, p6, p7, p114, None, i100, i93, i84, None, None, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -i122 = int_sub(i103, 1) -i124 = int_sub(i122, 1) -i125 = uint_floordiv(i124, i116) -i127 = int_add(i125, 1) -i129 = int_lt(i127, 0) -guard_false(i129, descr=<Guard220>) [p1, p0, p12, i116, i127, p2, p3, p22, p4, p5, p6, p7, p114, i103, i100, i93, i84, None, None, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #124 GET_ITER', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #125 FOR_ITER', 1) -i131 = int_gt(i127, 0) -guard_true(i131, descr=<Guard221>) [p1, p0, p12, p2, p3, p22, p4, p5, p6, p7, i116, i127, None, None, i100, i93, i84, None, None, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -i132 = int_add(1, i116) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #128 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #131 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #134 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #137 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #140 BINARY_MULTIPLY', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #141 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #144 BINARY_ADD', 1) -i133 = int_add_ovf(i66, 1) -guard_no_overflow(, descr=<Guard222>) [p1, p0, p12, i133, p2, p3, p22, p4, p5, p6, p7, i132, i125, i66, i116, None, None, None, i100, i93, i84, None, None, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #145 BINARY_SUBSCR', 1) -i134 = getfield_gc(p52, descr=<SignedFieldDescr pypy.module.array.interp_array.W_ArrayTyped.inst_len 32>) -i135 = int_lt(i133, i134) -guard_true(i135, descr=<Guard223>) [p1, p0, p12, p52, i133, p2, p3, p22, p4, p5, p6, p7, i132, i125, None, i116, None, None, None, i100, i93, i84, None, None, None, None, None, p50, p48, f47, f42, f38, None, p13, i28, i8] -i136 = getfield_gc(p52, descr=<NonGcPtrFieldDescr pypy.module.array.interp_array.W_ArrayTyped.inst_buffer 24>) -f137 = getarrayitem_raw(i136, i133, descr=<FloatArrayNoLengthDescr>) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #146 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #149 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #152 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #155 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #158 BINARY_SUBTRACT', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #159 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #162 BINARY_MULTIPLY', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #163 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #166 BINARY_ADD', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #167 BINARY_SUBSCR', 1) -f138 = getarrayitem_raw(i136, 1, descr=<FloatArrayNoLengthDescr>) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #168 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #171 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #174 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #177 BINARY_ADD', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #178 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #181 BINARY_MULTIPLY', 1) -i140 = int_mul_ovf(2, i66) -guard_no_overflow(, descr=<Guard224>) [p1, p0, p12, p48, i140, p2, p3, p22, p4, p5, p6, p7, f138, f137, i132, i125, None, i116, None, None, None, i100, i93, i84, None, None, None, None, p52, p50, None, f47, f42, f38, None, p13, i28, i8] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #182 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #185 BINARY_ADD', 1) -i141 = int_add_ovf(i140, 1) -guard_no_overflow(, descr=<Guard225>) [p1, p0, p12, i141, p2, p3, p22, p4, p5, p6, p7, i140, f138, f137, i132, i125, None, i116, None, None, None, i100, i93, i84, None, None, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #186 BINARY_SUBSCR', 1) -i143 = int_lt(i141, 0) -guard_false(i143, descr=<Guard226>) [p1, p0, p12, p52, i141, i134, p2, p3, p22, p4, p5, p6, p7, None, f138, f137, i132, i125, None, i116, None, None, None, i100, i93, i84, None, None, None, None, None, p50, p48, f47, f42, f38, None, p13, i28, i8] -i144 = int_lt(i141, i134) -guard_true(i144, descr=<Guard227>) [p1, p0, p12, p52, i141, p2, p3, p22, p4, p5, p6, p7, None, f138, f137, i132, i125, None, i116, None, None, None, i100, i93, i84, None, None, None, None, None, p50, p48, f47, f42, f38, None, p13, i28, i8] -f145 = getarrayitem_raw(i136, i141, descr=<FloatArrayNoLengthDescr>) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #187 BINARY_ADD', 1) -f146 = float_add(f138, f145) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #188 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #191 BINARY_MULTIPLY', 1) -f147 = float_mul(f146, f42) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #192 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #195 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #198 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #201 BINARY_MULTIPLY', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #202 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #205 BINARY_ADD', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #206 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #209 BINARY_SUBTRACT', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #210 BINARY_SUBSCR', 1) -i148 = int_lt(i66, i134) -guard_true(i148, descr=<Guard228>) [p1, p0, p12, p52, i66, p2, p3, p22, p4, p5, p6, p7, f147, None, None, f137, i132, i125, None, i116, None, None, None, i100, i93, i84, None, None, None, None, None, p50, p48, f47, f42, f38, None, p13, i28, i8] -f149 = getarrayitem_raw(i136, i66, descr=<FloatArrayNoLengthDescr>) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #211 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #214 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #217 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #220 BINARY_MULTIPLY', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #221 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #224 BINARY_ADD', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #225 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #228 BINARY_ADD', 1) -i151 = int_add(i133, 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #229 BINARY_SUBSCR', 1) -i152 = int_lt(i151, i134) -guard_true(i152, descr=<Guard229>) [p1, p0, p12, p52, i151, p2, p3, p22, p4, p5, p6, p7, f149, f147, None, None, f137, i132, i125, None, i116, None, None, None, i100, i93, i84, None, None, None, None, None, p50, p48, f47, f42, f38, None, p13, i28, i8] -f153 = getarrayitem_raw(i136, i151, descr=<FloatArrayNoLengthDescr>) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #230 BINARY_ADD', 1) -f154 = float_add(f149, f153) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #231 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #234 BINARY_MULTIPLY', 1) -f155 = float_mul(f154, f38) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #235 BINARY_ADD', 1) -f156 = float_add(f147, f155) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #236 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #239 BINARY_MULTIPLY', 1) -f157 = float_mul(f156, f47) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #240 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #243 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #246 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #249 BINARY_MULTIPLY', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #250 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #253 BINARY_ADD', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #254 STORE_SUBSCR', 1) -setarrayitem_raw(i136, i133, f157, descr=<FloatArrayNoLengthDescr>) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #255 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #258 LOAD_GLOBAL', 1) -p159 = getfield_gc(ConstPtr(ptr158), descr=<GcPtrFieldDescr pypy.objspace.std.celldict.ModuleCell.inst_w_value 8>) -guard_nonnull_class(p159, ConstClass(Function), descr=<Guard230>) [p1, p0, p12, p159, p2, p3, p22, p4, p5, p6, p7, None, None, None, None, f137, i132, i125, None, i116, None, None, None, i100, i93, i84, None, None, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #261 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #264 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #267 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #270 BINARY_MULTIPLY', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #271 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #274 BINARY_ADD', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #275 BINARY_SUBSCR', 1) -f161 = getarrayitem_raw(i136, i133, descr=<FloatArrayNoLengthDescr>) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #276 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #279 BINARY_SUBTRACT', 1) -f162 = float_sub(f161, f137) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #280 CALL_FUNCTION', 1) -p163 = getfield_gc(p159, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_code 24>) -guard_value(p163, ConstPtr(ptr164), descr=<Guard231>) [p1, p0, p12, p163, p159, p2, p3, p22, p4, p5, p6, p7, f162, None, None, None, None, f137, i132, i125, None, i116, None, None, None, i100, i93, i84, None, None, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -p165 = getfield_gc(p159, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_w_func_globals 64>) -p166 = getfield_gc(p159, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_closure 16>) -i167 = force_token() -debug_merge_point('<code object sqr, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 7> #0 LOAD_FAST', 2) -debug_merge_point('<code object sqr, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 7> #3 LOAD_FAST', 2) -debug_merge_point('<code object sqr, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 7> #6 BINARY_MULTIPLY', 2) -f168 = float_mul(f162, f162) -debug_merge_point('<code object sqr, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 7> #7 RETURN_VALUE', 2) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #283 INPLACE_ADD', 1) -f170 = float_add(0.000000, f168) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #284 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #287 JUMP_ABSOLUTE', 1) -i172 = getfield_raw(38968960, descr=<SignedFieldDescr pypysig_long_struct.c_value 0>) -i174 = int_sub(i172, 100) -setfield_raw(38968960, i174, descr=<SignedFieldDescr pypysig_long_struct.c_value 0>) -i176 = int_lt(i174, 0) -guard_false(i176, descr=<Guard232>) [p1, p0, p12, p2, p3, p22, p4, p5, p6, p7, f170, None, None, None, None, None, f137, i132, i125, None, i116, None, None, None, i100, i93, i84, None, None, None, None, p52, p50, p48, f47, f42, f38, None, p13, i28, i8] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #125 FOR_ITER', 1) -i177 = force_token() -p179 = new_with_vtable(19809200) -setfield_gc(p179, i28, descr=<SignedFieldDescr JitVirtualRef.virtual_token 8>) -setfield_gc(p12, p179, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref 56>) -setfield_gc(p0, i177, descr=<SignedFieldDescr pypy.interpreter.pyframe.PyFrame.vable_token 24>) -p181 = new_with_vtable(19863424) -setfield_gc(p181, p13, descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_f_backref 48>) -setfield_gc(p181, ConstPtr(ptr54), descr=<GcPtrFieldDescr pypy.interpreter.eval.Frame.inst_w_globals 8>) -setfield_gc(p181, 34, descr=<INTFieldDescr pypy.interpreter.pyframe.PyFrame.inst_f_lineno 144>) -setfield_gc(p181, ConstPtr(ptr25), descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_pycode 112>) -p184 = new_array(8, descr=<GcPtrArrayDescr>) -p186 = new_with_vtable(19861240) -setfield_gc(p186, i100, descr=<SignedFieldDescr pypy.module.__builtin__.functional.W_XRangeIterator.inst_current 8>) -setfield_gc(p186, i93, descr=<SignedFieldDescr pypy.module.__builtin__.functional.W_XRangeIterator.inst_remaining 16>) -setfield_gc(p186, i84, descr=<SignedFieldDescr pypy.module.__builtin__.functional.W_XRangeIterator.inst_step 24>) -setarrayitem_gc(p184, 0, p186, descr=<GcPtrArrayDescr>) -p189 = new_with_vtable(19861240) -setfield_gc(p189, i132, descr=<SignedFieldDescr pypy.module.__builtin__.functional.W_XRangeIterator.inst_current 8>) -setfield_gc(p189, i125, descr=<SignedFieldDescr pypy.module.__builtin__.functional.W_XRangeIterator.inst_remaining 16>) -setfield_gc(p189, i116, descr=<SignedFieldDescr pypy.module.__builtin__.functional.W_XRangeIterator.inst_step 24>) -setarrayitem_gc(p184, 1, p189, descr=<GcPtrArrayDescr>) -setfield_gc(p181, p184, descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_valuestack_w 120>) -setfield_gc(p181, 125, descr=<SignedFieldDescr pypy.interpreter.pyframe.PyFrame.inst_last_instr 96>) -p193 = new_with_vtable(19865144) -setfield_gc(p193, 291, descr=<UnsignedFieldDescr pypy.interpreter.pyopcode.FrameBlock.inst_handlerposition 8>) -setfield_gc(p193, 1, descr=<SignedFieldDescr pypy.interpreter.pyopcode.FrameBlock.inst_valuestackdepth 24>) -p197 = new_with_vtable(19865144) -setfield_gc(p197, 295, descr=<UnsignedFieldDescr pypy.interpreter.pyopcode.FrameBlock.inst_handlerposition 8>) -setfield_gc(p193, p197, descr=<GcPtrFieldDescr pypy.interpreter.pyopcode.FrameBlock.inst_previous 16>) -setfield_gc(p181, p193, descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_lastblock 104>) -p200 = new_array(11, descr=<GcPtrArrayDescr>) -setarrayitem_gc(p200, 0, p4, descr=<GcPtrArrayDescr>) -p203 = new_with_vtable(19800744) -setfield_gc(p203, f38, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -setarrayitem_gc(p200, 1, p203, descr=<GcPtrArrayDescr>) -p206 = new_with_vtable(19800744) -setfield_gc(p206, f42, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -setarrayitem_gc(p200, 2, p206, descr=<GcPtrArrayDescr>) -p209 = new_with_vtable(19800744) -setfield_gc(p209, f47, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -setarrayitem_gc(p200, 3, p209, descr=<GcPtrArrayDescr>) -p212 = new_with_vtable(19800744) -setfield_gc(p212, f170, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -setarrayitem_gc(p200, 4, p212, descr=<GcPtrArrayDescr>) -setarrayitem_gc(p200, 5, p48, descr=<GcPtrArrayDescr>) -setarrayitem_gc(p200, 6, p50, descr=<GcPtrArrayDescr>) -setarrayitem_gc(p200, 7, p52, descr=<GcPtrArrayDescr>) -p218 = new_with_vtable(ConstClass(W_IntObject)) -setfield_gc(p218, 1, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval 8>) -setarrayitem_gc(p200, 8, p218, descr=<GcPtrArrayDescr>) -p221 = new_with_vtable(ConstClass(W_IntObject)) -setfield_gc(p221, 1, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval 8>) -setarrayitem_gc(p200, 9, p221, descr=<GcPtrArrayDescr>) -p224 = new_with_vtable(19800744) -setfield_gc(p224, f137, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -setarrayitem_gc(p200, 10, p224, descr=<GcPtrArrayDescr>) -setfield_gc(p181, p200, descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_fastlocals_w 56>) -setfield_gc(p181, 2, descr=<SignedFieldDescr pypy.interpreter.pyframe.PyFrame.inst_valuestackdepth 128>) -p235 = call_assembler(p181, p12, ConstPtr(ptr25), p193, 2, ConstPtr(ptr227), 0, 125, p186, p189, ConstPtr(ptr229), ConstPtr(ptr230), ConstPtr(ptr231), ConstPtr(ptr232), ConstPtr(ptr233), ConstPtr(ptr234), p4, p203, p206, p209, p212, p48, p50, p52, p218, p221, p224, descr=<Loop1>) -guard_not_forced(, descr=<Guard233>) [p1, p0, p12, p181, p235, p179, p2, p3, p22, p4, p5, p6, p7, i8] -guard_no_exception(, descr=<Guard234>) [p1, p0, p12, p181, p235, p179, p2, p3, p22, p4, p5, p6, p7, i8] -p236 = getfield_gc(p12, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc 72>) -guard_isnull(p236, descr=<Guard235>) [p1, p0, p12, p235, p181, p236, p179, p2, p3, p22, p4, p5, p6, p7, i8] -i237 = ptr_eq(p181, p0) -guard_false(i237, descr=<Guard236>) [p1, p0, p12, p235, p181, p179, p2, p3, p22, p4, p5, p6, p7, i8] -i238 = getfield_gc(p12, descr=<NonGcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc 40>) -setfield_gc(p181, ConstPtr(ptr239), descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_last_exception 88>) -i240 = int_is_true(i238) -guard_false(i240, descr=<Guard237>) [p1, p0, p235, p181, p12, p179, p2, p3, p22, p4, p5, p6, p7, i8] -p241 = getfield_gc(p181, descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_f_backref 48>) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #64 STORE_FAST', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #67 LOAD_FAST', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #70 LOAD_CONST', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #73 INPLACE_ADD', 0) -i243 = int_add(i8, 1) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #74 STORE_FAST', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #77 JUMP_ABSOLUTE', 0) -i245 = getfield_raw(38968960, descr=<SignedFieldDescr pypysig_long_struct.c_value 0>) -i247 = int_sub(i245, 100) -setfield_raw(38968960, i247, descr=<SignedFieldDescr pypysig_long_struct.c_value 0>) -setfield_gc(p12, p241, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref 56>) -setfield_gc(p179, p181, descr=<GcPtrFieldDescr JitVirtualRef.forced 16>) -setfield_gc(p179, -3, descr=<SignedFieldDescr JitVirtualRef.virtual_token 8>) -i250 = int_lt(i247, 0) -guard_false(i250, descr=<Guard238>) [p1, p0, p2, p3, p4, p5, p6, p235, i243, None] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #21 LOAD_FAST', 0) -jump(p0, p1, p2, p3, p4, p5, p6, p235, i243, f9, i10, i238, p12, p241, descr=<Loop2>) -[5ed74fc965fa] jit-log-opt-loop} -[5ed74fe43ee0] {jit-log-opt-loop -# Loop 3 : entry bridge with 413 ops -[p0, p1, p2, p3, i4, p5, i6, i7, p8, p9, p10, p11, p12, p13, p14] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #21 LOAD_FAST', 0) -guard_value(i4, 0, descr=<Guard239>) [i4, p1, p0, p2, p3, p5, i6, i7, p8, p9, p10, p11, p12, p13, p14] -guard_nonnull_class(p13, 19800744, descr=<Guard240>) [p1, p0, p13, p2, p3, p5, i6, p8, p9, p10, p11, p12, p14] -guard_value(i6, 0, descr=<Guard241>) [i6, p1, p0, p2, p3, p5, p13, p9, p10, p11, p12, p14] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #24 LOAD_FAST', 0) -guard_nonnull_class(p12, 19800744, descr=<Guard242>) [p1, p0, p12, p2, p3, p5, p13, p9, p10, p11, p14] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #27 COMPARE_OP', 0) -f19 = getfield_gc_pure(p13, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -f20 = getfield_gc_pure(p12, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -i21 = float_gt(f19, f20) -guard_true(i21, descr=<Guard243>) [p1, p0, p12, p13, p2, p3, p5, p10, p11, p14] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #30 POP_JUMP_IF_FALSE', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #33 LOAD_FAST', 0) -guard_nonnull_class(p11, ConstClass(W_IntObject), descr=<Guard244>) [p1, p0, p11, p2, p3, p5, p10, p12, p13, p14] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #36 POP_JUMP_IF_FALSE', 0) -i23 = getfield_gc_pure(p11, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval 8>) -i24 = int_is_true(i23) -guard_true(i24, descr=<Guard245>) [p1, p0, p11, p2, p3, p5, p10, p12, p13, p14] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #39 LOAD_FAST', 0) -guard_nonnull_class(p14, ConstClass(W_IntObject), descr=<Guard246>) [p1, p0, p14, p2, p3, p5, p10, p11, p12, p13] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #42 LOAD_FAST', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #45 COMPARE_OP', 0) -i26 = getfield_gc_pure(p14, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval 8>) -i27 = int_ge(i26, i23) -guard_false(i27, descr=<Guard247>) [p1, p0, p11, p14, p2, p3, p5, p10, p12, p13] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #48 POP_JUMP_IF_FALSE', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #55 LOAD_GLOBAL', 0) -guard_value(p2, ConstPtr(ptr28), descr=<Guard248>) [p1, p0, p2, p3, p5, p10, p11, p12, p13, p14] -p29 = getfield_gc(p0, descr=<GcPtrFieldDescr pypy.interpreter.eval.Frame.inst_w_globals 8>) -guard_value(p29, ConstPtr(ptr30), descr=<Guard249>) [p1, p0, p29, p3, p5, p10, p11, p12, p13, p14] -p31 = getfield_gc(p29, descr=<GcPtrFieldDescr pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_r_dict_content 8>) -guard_isnull(p31, descr=<Guard250>) [p1, p0, p31, p29, p3, p5, p10, p11, p12, p13, p14] -p33 = getfield_gc(ConstPtr(ptr32), descr=<GcPtrFieldDescr pypy.objspace.std.celldict.ModuleCell.inst_w_value 8>) -guard_nonnull_class(p33, ConstClass(Function), descr=<Guard251>) [p1, p0, p33, p3, p5, p10, p11, p12, p13, p14] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #58 LOAD_FAST', 0) -guard_nonnull_class(p10, 19852624, descr=<Guard252>) [p1, p0, p10, p3, p5, p33, p11, p12, p13, p14] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #61 CALL_FUNCTION', 0) -p36 = getfield_gc(p33, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_code 24>) -guard_value(p36, ConstPtr(ptr37), descr=<Guard253>) [p1, p0, p36, p33, p3, p5, p10, p11, p12, p13, p14] -p38 = getfield_gc(p33, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_w_func_globals 64>) -p39 = getfield_gc(p33, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_closure 16>) -p41 = call(ConstClass(getexecutioncontext), descr=<GcPtrCallDescr>) -p42 = getfield_gc(p41, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref 56>) -i43 = force_token() -p44 = getfield_gc(p41, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc 72>) -guard_isnull(p44, descr=<Guard254>) [p1, p0, p41, p44, p3, p5, p33, p10, p11, p12, p13, p14, i43, p42, p38] -i45 = getfield_gc(p41, descr=<NonGcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc 40>) -i46 = int_is_zero(i45) -guard_true(i46, descr=<Guard255>) [p1, p0, p41, p3, p5, p33, p10, p11, p12, p13, p14, i43, p42, p38] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #0 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #3 LOAD_ATTR', 1) -p47 = getfield_gc(p10, descr=<GcPtrFieldDescr pypy.objspace.std.mapdict.W_ObjectObjectSize5.inst_map 48>) -guard_value(p47, ConstPtr(ptr48), descr=<Guard256>) [p1, p0, p41, p10, p47, p3, p5, p33, p11, p12, p13, p14, i43, p42, p38] -p50 = getfield_gc(ConstPtr(ptr49), descr=<GcPtrFieldDescr pypy.objspace.std.typeobject.W_TypeObject.inst__version_tag 16>) -guard_value(p50, ConstPtr(ptr51), descr=<Guard257>) [p1, p0, p41, p10, p50, p3, p5, p33, p11, p12, p13, p14, i43, p42, p38] -p52 = getfield_gc(p10, descr=<GcPtrFieldDescr pypy.objspace.std.mapdict.W_ObjectObjectSize5.inst__value2 24>) -guard_nonnull_class(p52, 19800744, descr=<Guard258>) [p1, p0, p41, p52, p10, p3, p5, p33, p11, p12, p13, p14, i43, p42, p38] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #6 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #9 LOAD_ATTR', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #12 BINARY_MULTIPLY', 1) -f54 = getfield_gc_pure(p52, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -f55 = float_mul(f54, f54) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #13 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #16 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #19 LOAD_ATTR', 1) -p56 = getfield_gc(p10, descr=<GcPtrFieldDescr pypy.objspace.std.mapdict.W_ObjectObjectSize5.inst__value3 32>) -guard_nonnull_class(p56, 19800744, descr=<Guard259>) [p1, p0, p41, p56, p10, p3, p5, p33, p11, p12, p13, p14, f55, i43, p42, p38] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #22 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #25 LOAD_ATTR', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #28 BINARY_MULTIPLY', 1) -f58 = getfield_gc_pure(p56, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -f59 = float_mul(f58, f58) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #29 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #32 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #35 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #38 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #41 BINARY_ADD', 1) -f60 = float_add(f55, f59) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #42 BINARY_DIVIDE', 1) -i62 = float_eq(f60, 0.000000) -guard_false(i62, descr=<Guard260>) [p1, p0, p41, f60, p3, p5, p33, p10, p11, p12, p13, p14, f59, f55, i43, p42, p38] -f64 = float_truediv(0.500000, f60) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #43 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #46 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #49 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #52 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #55 LOAD_ATTR', 1) -p65 = getfield_gc(p10, descr=<GcPtrFieldDescr pypy.objspace.std.mapdict.W_ObjectObjectSize5.inst__value0 8>) -guard_nonnull_class(p65, ConstClass(W_IntObject), descr=<Guard261>) [p1, p0, p41, p65, p10, p3, p5, p33, p11, p12, p13, p14, f64, f59, f55, i43, p42, p38] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #58 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #61 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #64 LOAD_ATTR', 1) -p67 = getfield_gc(p10, descr=<GcPtrFieldDescr pypy.objspace.std.mapdict.W_ObjectObjectSize5.inst__value1 16>) -guard_nonnull_class(p67, ConstClass(W_IntObject), descr=<Guard262>) [p1, p0, p41, p67, p10, p3, p5, p33, p11, p12, p13, p14, p65, f64, f59, f55, i43, p42, p38] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #67 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #70 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #73 LOAD_ATTR', 1) -p69 = getfield_gc(p10, descr=<GcPtrFieldDescr pypy.objspace.std.mapdict.W_ObjectObjectSize5.inst__value4 40>) -guard_nonnull_class(p69, 19886912, descr=<Guard263>) [p1, p0, p41, p69, p10, p3, p5, p33, p11, p12, p13, p14, p67, p65, f64, f59, f55, i43, p42, p38] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #76 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #79 SETUP_LOOP', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #82 LOAD_GLOBAL', 1) -guard_value(p38, ConstPtr(ptr71), descr=<Guard264>) [p1, p0, p41, p38, p3, p5, p33, p10, p11, p12, p13, p14, p69, p67, p65, f64, f59, f55, i43, p42, None] -p73 = getfield_gc(p38, descr=<GcPtrFieldDescr pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_r_dict_content 8>) -guard_isnull(p73, descr=<Guard265>) [p1, p0, p41, p73, p38, p3, p5, p33, p10, p11, p12, p13, p14, p69, p67, p65, f64, f59, f55, i43, p42, None] -p75 = getfield_gc(ConstPtr(ptr74), descr=<GcPtrFieldDescr pypy.objspace.std.celldict.ModuleCell.inst_w_value 8>) -guard_isnull(p75, descr=<Guard266>) [p1, p0, p41, p75, p3, p5, p33, p10, p11, p12, p13, p14, p69, p67, p65, f64, f59, f55, i43, p42, None] -p77 = getfield_gc(ConstPtr(ptr76), descr=<GcPtrFieldDescr pypy.interpreter.module.Module.inst_w_dict 8>) -guard_value(p77, ConstPtr(ptr78), descr=<Guard267>) [p1, p0, p41, p77, p3, p5, p33, p10, p11, p12, p13, p14, p69, p67, p65, f64, f59, f55, i43, p42, None] -p79 = getfield_gc(p77, descr=<GcPtrFieldDescr pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_r_dict_content 8>) -guard_isnull(p79, descr=<Guard268>) [p1, p0, p41, p79, p77, p3, p5, p33, p10, p11, p12, p13, p14, p69, p67, p65, f64, f59, f55, i43, p42, None] -p81 = getfield_gc(ConstPtr(ptr80), descr=<GcPtrFieldDescr pypy.objspace.std.celldict.ModuleCell.inst_w_value 8>) -guard_value(p81, ConstPtr(ptr82), descr=<Guard269>) [p1, p0, p41, p81, p3, p5, p33, p10, p11, p12, p13, p14, p69, p67, p65, f64, f59, f55, i43, p42, None] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #85 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #88 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #91 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #94 BINARY_SUBTRACT', 1) -i83 = getfield_gc_pure(p65, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval 8>) -i85 = int_sub_ovf(i83, 1) -guard_no_overflow(, descr=<Guard270>) [p1, p0, p41, p65, i85, p3, p5, p33, p10, p11, p12, p13, p14, p81, p69, p67, None, f64, f59, f55, i43, p42, None] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #95 CALL_FUNCTION', 1) -p87 = getfield_gc(ConstPtr(ptr86), descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_name 40>) -p88 = getfield_gc(ConstPtr(ptr86), descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_defs 32>) -i89 = getfield_gc_pure(p88, descr=<BoolFieldDescr pypy.interpreter.function.Defaults.inst_promote 16>) -guard_false(i89, descr=<Guard271>) [p1, p0, p41, p87, p88, p3, p5, p33, p10, p11, p12, p13, p14, i85, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -p90 = getfield_gc_pure(p88, descr=<GcPtrFieldDescr pypy.interpreter.function.Defaults.inst_items 8>) -i91 = arraylen_gc(p90, descr=<GcPtrArrayDescr>) -i93 = int_sub(4, i91) -i95 = int_ge(3, i93) -guard_true(i95, descr=<Guard272>) [p1, p0, p41, p87, i93, p88, p3, p5, p33, p10, p11, p12, p13, p14, i85, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -i96 = int_sub(3, i93) -i97 = getfield_gc_pure(p88, descr=<BoolFieldDescr pypy.interpreter.function.Defaults.inst_promote 16>) -guard_false(i97, descr=<Guard273>) [p1, p0, p41, p87, i96, i93, p88, p3, p5, p33, p10, p11, p12, p13, p14, i85, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -p98 = getfield_gc_pure(p88, descr=<GcPtrFieldDescr pypy.interpreter.function.Defaults.inst_items 8>) -p99 = getarrayitem_gc(p98, i96, descr=<GcPtrArrayDescr>) -guard_class(p99, ConstClass(W_IntObject), descr=<Guard274>) [p1, p0, p41, p99, p3, p5, p33, p10, p11, p12, p13, p14, i85, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -i101 = getfield_gc_pure(p99, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval 8>) -i102 = int_is_zero(i101) -guard_false(i102, descr=<Guard275>) [p1, p0, p41, i101, i85, p3, p5, p33, p10, p11, p12, p13, p14, p99, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -i104 = int_lt(i101, 0) -guard_false(i104, descr=<Guard276>) [p1, p0, p41, i101, i85, p3, p5, p33, p10, p11, p12, p13, p14, p99, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -i106 = int_lt(1, i85) -guard_true(i106, descr=<Guard277>) [p1, p0, p41, i101, i85, p3, p5, p33, p10, p11, p12, p13, p14, p99, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -i107 = int_sub(i85, 1) -i109 = int_sub(i107, 1) -i110 = uint_floordiv(i109, i101) -i112 = int_add(i110, 1) -i114 = int_lt(i112, 0) -guard_false(i114, descr=<Guard278>) [p1, p0, p41, i101, i112, p3, p5, p33, p10, p11, p12, p13, p14, p99, i85, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #98 GET_ITER', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #99 FOR_ITER', 1) -i116 = int_gt(i112, 0) -guard_true(i116, descr=<Guard279>) [p1, p0, p41, p3, p5, p33, p10, p11, p12, p13, p14, i112, i101, None, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -i117 = int_add(1, i101) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #102 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #105 SETUP_LOOP', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #108 LOAD_GLOBAL', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #111 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #114 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #117 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #120 BINARY_SUBTRACT', 1) -i118 = getfield_gc_pure(p67, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval 8>) -i120 = int_sub_ovf(i118, 1) -guard_no_overflow(, descr=<Guard280>) [p1, p0, p41, p67, i120, p3, p5, p33, p10, p11, p12, p13, p14, i110, i117, None, i101, None, None, None, p69, None, p65, f64, f59, f55, i43, p42, None] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #121 CALL_FUNCTION', 1) -i121 = getfield_gc_pure(p88, descr=<BoolFieldDescr pypy.interpreter.function.Defaults.inst_promote 16>) -guard_false(i121, descr=<Guard281>) [p1, p0, p41, p87, p88, p3, p5, p33, p10, p11, p12, p13, p14, i120, i110, i117, None, i101, None, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -p122 = getfield_gc_pure(p88, descr=<GcPtrFieldDescr pypy.interpreter.function.Defaults.inst_items 8>) -i123 = arraylen_gc(p122, descr=<GcPtrArrayDescr>) -i125 = int_sub(4, i123) -i127 = int_ge(3, i125) -guard_true(i127, descr=<Guard282>) [p1, p0, p41, p87, i125, p88, p3, p5, p33, p10, p11, p12, p13, p14, i120, i110, i117, None, i101, None, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -i128 = int_sub(3, i125) -i129 = getfield_gc_pure(p88, descr=<BoolFieldDescr pypy.interpreter.function.Defaults.inst_promote 16>) -guard_false(i129, descr=<Guard283>) [p1, p0, p41, p87, i128, i125, p88, p3, p5, p33, p10, p11, p12, p13, p14, i120, i110, i117, None, i101, None, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -p130 = getfield_gc_pure(p88, descr=<GcPtrFieldDescr pypy.interpreter.function.Defaults.inst_items 8>) -p131 = getarrayitem_gc(p130, i128, descr=<GcPtrArrayDescr>) -guard_class(p131, ConstClass(W_IntObject), descr=<Guard284>) [p1, p0, p41, p131, p3, p5, p33, p10, p11, p12, p13, p14, i120, i110, i117, None, i101, None, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -i133 = getfield_gc_pure(p131, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval 8>) -i134 = int_is_zero(i133) -guard_false(i134, descr=<Guard285>) [p1, p0, p41, i133, i120, p3, p5, p33, p10, p11, p12, p13, p14, p131, None, i110, i117, None, i101, None, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -i136 = int_lt(i133, 0) -guard_false(i136, descr=<Guard286>) [p1, p0, p41, i133, i120, p3, p5, p33, p10, p11, p12, p13, p14, p131, None, i110, i117, None, i101, None, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -i138 = int_lt(1, i120) -guard_true(i138, descr=<Guard287>) [p1, p0, p41, i133, i120, p3, p5, p33, p10, p11, p12, p13, p14, p131, None, i110, i117, None, i101, None, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -i139 = int_sub(i120, 1) -i141 = int_sub(i139, 1) -i142 = uint_floordiv(i141, i133) -i144 = int_add(i142, 1) -i146 = int_lt(i144, 0) -guard_false(i146, descr=<Guard288>) [p1, p0, p41, i133, i144, p3, p5, p33, p10, p11, p12, p13, p14, p131, i120, i110, i117, None, i101, None, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #124 GET_ITER', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #125 FOR_ITER', 1) -i148 = int_gt(i144, 0) -guard_true(i148, descr=<Guard289>) [p1, p0, p41, p3, p5, p33, p10, p11, p12, p13, p14, i144, i133, None, None, i110, i117, None, i101, None, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -i149 = int_add(1, i133) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #128 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #131 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #134 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #137 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #140 BINARY_MULTIPLY', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #141 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #144 BINARY_ADD', 1) -i150 = int_add_ovf(i83, 1) -guard_no_overflow(, descr=<Guard290>) [p1, p0, p41, i150, p3, p5, p33, p10, p11, p12, p13, p14, i83, i149, i142, None, i133, None, None, i110, i117, None, i101, None, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #145 BINARY_SUBSCR', 1) -i151 = getfield_gc(p69, descr=<SignedFieldDescr pypy.module.array.interp_array.W_ArrayTyped.inst_len 32>) -i152 = int_lt(i150, i151) -guard_true(i152, descr=<Guard291>) [p1, p0, p41, p69, i150, p3, p5, p33, p10, p11, p12, p13, p14, None, i149, i142, None, i133, None, None, i110, i117, None, i101, None, None, None, None, p67, p65, f64, f59, f55, i43, p42, None] -i153 = getfield_gc(p69, descr=<NonGcPtrFieldDescr pypy.module.array.interp_array.W_ArrayTyped.inst_buffer 24>) -f154 = getarrayitem_raw(i153, i150, descr=<FloatArrayNoLengthDescr>) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #146 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #149 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #152 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #155 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #158 BINARY_SUBTRACT', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #159 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #162 BINARY_MULTIPLY', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #163 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #166 BINARY_ADD', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #167 BINARY_SUBSCR', 1) -f155 = getarrayitem_raw(i153, 1, descr=<FloatArrayNoLengthDescr>) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #168 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #171 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #174 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #177 BINARY_ADD', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #178 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #181 BINARY_MULTIPLY', 1) -i157 = int_mul_ovf(2, i83) -guard_no_overflow(, descr=<Guard292>) [p1, p0, p41, p65, i157, p3, p5, p33, p10, p11, p12, p13, p14, f154, f155, None, i149, i142, None, i133, None, None, i110, i117, None, i101, None, None, None, p69, p67, None, f64, f59, f55, i43, p42, None] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #182 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #185 BINARY_ADD', 1) -i158 = int_add_ovf(i157, 1) -guard_no_overflow(, descr=<Guard293>) [p1, p0, p41, i158, p3, p5, p33, p10, p11, p12, p13, p14, i157, f154, f155, None, i149, i142, None, i133, None, None, i110, i117, None, i101, None, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #186 BINARY_SUBSCR', 1) -i160 = int_lt(i158, 0) -guard_false(i160, descr=<Guard294>) [p1, p0, p41, p69, i158, i151, p3, p5, p33, p10, p11, p12, p13, p14, None, f154, f155, None, i149, i142, None, i133, None, None, i110, i117, None, i101, None, None, None, None, p67, p65, f64, f59, f55, i43, p42, None] -i161 = int_lt(i158, i151) -guard_true(i161, descr=<Guard295>) [p1, p0, p41, p69, i158, p3, p5, p33, p10, p11, p12, p13, p14, None, f154, f155, None, i149, i142, None, i133, None, None, i110, i117, None, i101, None, None, None, None, p67, p65, f64, f59, f55, i43, p42, None] -f162 = getarrayitem_raw(i153, i158, descr=<FloatArrayNoLengthDescr>) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #187 BINARY_ADD', 1) -f163 = float_add(f155, f162) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #188 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #191 BINARY_MULTIPLY', 1) -f164 = float_mul(f163, f59) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #192 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #195 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #198 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #201 BINARY_MULTIPLY', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #202 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #205 BINARY_ADD', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #206 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #209 BINARY_SUBTRACT', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #210 BINARY_SUBSCR', 1) -i165 = int_lt(i83, i151) -guard_true(i165, descr=<Guard296>) [p1, p0, p41, p69, i83, p3, p5, p33, p10, p11, p12, p13, p14, f164, None, f154, None, None, i149, i142, None, i133, None, None, i110, i117, None, i101, None, None, None, None, p67, p65, f64, f59, f55, i43, p42, None] -f166 = getarrayitem_raw(i153, i83, descr=<FloatArrayNoLengthDescr>) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #211 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #214 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #217 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #220 BINARY_MULTIPLY', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #221 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #224 BINARY_ADD', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #225 LOAD_CONST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #228 BINARY_ADD', 1) -i168 = int_add(i150, 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #229 BINARY_SUBSCR', 1) -i169 = int_lt(i168, i151) -guard_true(i169, descr=<Guard297>) [p1, p0, p41, p69, i168, p3, p5, p33, p10, p11, p12, p13, p14, f166, f164, None, f154, None, None, i149, i142, None, i133, None, None, i110, i117, None, i101, None, None, None, None, p67, p65, f64, f59, f55, i43, p42, None] -f170 = getarrayitem_raw(i153, i168, descr=<FloatArrayNoLengthDescr>) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #230 BINARY_ADD', 1) -f171 = float_add(f166, f170) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #231 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #234 BINARY_MULTIPLY', 1) -f172 = float_mul(f171, f55) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #235 BINARY_ADD', 1) -f173 = float_add(f164, f172) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #236 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #239 BINARY_MULTIPLY', 1) -f174 = float_mul(f173, f64) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #240 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #243 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #246 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #249 BINARY_MULTIPLY', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #250 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #253 BINARY_ADD', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #254 STORE_SUBSCR', 1) -setarrayitem_raw(i153, i150, f174, descr=<FloatArrayNoLengthDescr>) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #255 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #258 LOAD_GLOBAL', 1) -p176 = getfield_gc(ConstPtr(ptr175), descr=<GcPtrFieldDescr pypy.objspace.std.celldict.ModuleCell.inst_w_value 8>) -guard_nonnull_class(p176, ConstClass(Function), descr=<Guard298>) [p1, p0, p41, p176, p3, p5, p33, p10, p11, p12, p13, p14, None, None, None, f154, None, None, i149, i142, None, i133, None, None, i110, i117, None, i101, None, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #261 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #264 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #267 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #270 BINARY_MULTIPLY', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #271 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #274 BINARY_ADD', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #275 BINARY_SUBSCR', 1) -f178 = getarrayitem_raw(i153, i150, descr=<FloatArrayNoLengthDescr>) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #276 LOAD_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #279 BINARY_SUBTRACT', 1) -f179 = float_sub(f178, f154) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #280 CALL_FUNCTION', 1) -p180 = getfield_gc(p176, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_code 24>) -guard_value(p180, ConstPtr(ptr181), descr=<Guard299>) [p1, p0, p41, p180, p176, p3, p5, p33, p10, p11, p12, p13, p14, f179, None, None, None, f154, None, None, i149, i142, None, i133, None, None, i110, i117, None, i101, None, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -p182 = getfield_gc(p176, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_w_func_globals 64>) -p183 = getfield_gc(p176, descr=<GcPtrFieldDescr pypy.interpreter.function.Function.inst_closure 16>) -i184 = force_token() -debug_merge_point('<code object sqr, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 7> #0 LOAD_FAST', 2) -debug_merge_point('<code object sqr, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 7> #3 LOAD_FAST', 2) -debug_merge_point('<code object sqr, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 7> #6 BINARY_MULTIPLY', 2) -f185 = float_mul(f179, f179) -debug_merge_point('<code object sqr, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 7> #7 RETURN_VALUE', 2) -i186 = int_is_true(i45) -guard_false(i186, descr=<Guard300>) [p1, p0, p41, p3, p5, p33, p10, p11, p12, p13, p14, p182, i184, p176, f185, f179, None, None, None, f154, None, None, i149, i142, None, i133, None, None, i110, i117, None, i101, None, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #283 INPLACE_ADD', 1) -f188 = float_add(0.000000, f185) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #284 STORE_FAST', 1) -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #287 JUMP_ABSOLUTE', 1) -i190 = getfield_raw(38968960, descr=<SignedFieldDescr pypysig_long_struct.c_value 0>) -i192 = int_sub(i190, 100) -setfield_raw(38968960, i192, descr=<SignedFieldDescr pypysig_long_struct.c_value 0>) -i194 = int_lt(i192, 0) -guard_false(i194, descr=<Guard301>) [p1, p0, p41, p3, p5, p33, p10, p11, p12, p13, p14, f188, None, None, None, None, None, None, None, None, f154, None, None, i149, i142, None, i133, None, None, i110, i117, None, i101, None, None, None, p69, p67, p65, f64, f59, f55, i43, p42, None] -debug_merge_point('<code object time_step, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 34> #125 FOR_ITER', 1) -i195 = force_token() -p197 = new_with_vtable(19809200) -setfield_gc(p197, i43, descr=<SignedFieldDescr JitVirtualRef.virtual_token 8>) -setfield_gc(p41, p197, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref 56>) -setfield_gc(p0, i195, descr=<SignedFieldDescr pypy.interpreter.pyframe.PyFrame.vable_token 24>) -p199 = new_with_vtable(19863424) -setfield_gc(p199, p42, descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_f_backref 48>) -setfield_gc(p199, ConstPtr(ptr71), descr=<GcPtrFieldDescr pypy.interpreter.eval.Frame.inst_w_globals 8>) -setfield_gc(p199, 34, descr=<INTFieldDescr pypy.interpreter.pyframe.PyFrame.inst_f_lineno 144>) -setfield_gc(p199, ConstPtr(ptr37), descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_pycode 112>) -p202 = new_array(8, descr=<GcPtrArrayDescr>) -p204 = new_with_vtable(19861240) -setfield_gc(p204, i117, descr=<SignedFieldDescr pypy.module.__builtin__.functional.W_XRangeIterator.inst_current 8>) -setfield_gc(p204, i110, descr=<SignedFieldDescr pypy.module.__builtin__.functional.W_XRangeIterator.inst_remaining 16>) -setfield_gc(p204, i101, descr=<SignedFieldDescr pypy.module.__builtin__.functional.W_XRangeIterator.inst_step 24>) -setarrayitem_gc(p202, 0, p204, descr=<GcPtrArrayDescr>) -p207 = new_with_vtable(19861240) -setfield_gc(p207, i149, descr=<SignedFieldDescr pypy.module.__builtin__.functional.W_XRangeIterator.inst_current 8>) -setfield_gc(p207, i142, descr=<SignedFieldDescr pypy.module.__builtin__.functional.W_XRangeIterator.inst_remaining 16>) -setfield_gc(p207, i133, descr=<SignedFieldDescr pypy.module.__builtin__.functional.W_XRangeIterator.inst_step 24>) -setarrayitem_gc(p202, 1, p207, descr=<GcPtrArrayDescr>) -setfield_gc(p199, p202, descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_valuestack_w 120>) -setfield_gc(p199, 125, descr=<SignedFieldDescr pypy.interpreter.pyframe.PyFrame.inst_last_instr 96>) -p211 = new_with_vtable(19865144) -setfield_gc(p211, 291, descr=<UnsignedFieldDescr pypy.interpreter.pyopcode.FrameBlock.inst_handlerposition 8>) -setfield_gc(p211, 1, descr=<SignedFieldDescr pypy.interpreter.pyopcode.FrameBlock.inst_valuestackdepth 24>) -p215 = new_with_vtable(19865144) -setfield_gc(p215, 295, descr=<UnsignedFieldDescr pypy.interpreter.pyopcode.FrameBlock.inst_handlerposition 8>) -setfield_gc(p211, p215, descr=<GcPtrFieldDescr pypy.interpreter.pyopcode.FrameBlock.inst_previous 16>) -setfield_gc(p199, p211, descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_lastblock 104>) -p218 = new_array(11, descr=<GcPtrArrayDescr>) -setarrayitem_gc(p218, 0, p10, descr=<GcPtrArrayDescr>) -p221 = new_with_vtable(19800744) -setfield_gc(p221, f55, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -setarrayitem_gc(p218, 1, p221, descr=<GcPtrArrayDescr>) -p224 = new_with_vtable(19800744) -setfield_gc(p224, f59, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -setarrayitem_gc(p218, 2, p224, descr=<GcPtrArrayDescr>) -p227 = new_with_vtable(19800744) -setfield_gc(p227, f64, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -setarrayitem_gc(p218, 3, p227, descr=<GcPtrArrayDescr>) -p230 = new_with_vtable(19800744) -setfield_gc(p230, f188, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -setarrayitem_gc(p218, 4, p230, descr=<GcPtrArrayDescr>) -setarrayitem_gc(p218, 5, p65, descr=<GcPtrArrayDescr>) -setarrayitem_gc(p218, 6, p67, descr=<GcPtrArrayDescr>) -setarrayitem_gc(p218, 7, p69, descr=<GcPtrArrayDescr>) -p236 = new_with_vtable(ConstClass(W_IntObject)) -setfield_gc(p236, 1, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval 8>) -setarrayitem_gc(p218, 8, p236, descr=<GcPtrArrayDescr>) -p239 = new_with_vtable(ConstClass(W_IntObject)) -setfield_gc(p239, 1, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval 8>) -setarrayitem_gc(p218, 9, p239, descr=<GcPtrArrayDescr>) -p242 = new_with_vtable(19800744) -setfield_gc(p242, f154, descr=<FloatFieldDescr pypy.objspace.std.floatobject.W_FloatObject.inst_floatval 8>) -setarrayitem_gc(p218, 10, p242, descr=<GcPtrArrayDescr>) -setfield_gc(p199, p218, descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_fastlocals_w 56>) -setfield_gc(p199, 2, descr=<SignedFieldDescr pypy.interpreter.pyframe.PyFrame.inst_valuestackdepth 128>) -p253 = call_assembler(p199, p41, ConstPtr(ptr37), p211, 2, ConstPtr(ptr245), 0, 125, p204, p207, ConstPtr(ptr247), ConstPtr(ptr248), ConstPtr(ptr249), ConstPtr(ptr250), ConstPtr(ptr251), ConstPtr(ptr252), p10, p221, p224, p227, p230, p65, p67, p69, p236, p239, p242, descr=<Loop1>) -guard_not_forced(, descr=<Guard302>) [p1, p0, p41, p199, p253, p197, p3, p5, p33, p10, p11, p12, p13, p14] -guard_no_exception(, descr=<Guard303>) [p1, p0, p41, p199, p253, p197, p3, p5, p33, p10, p11, p12, p13, p14] -p254 = getfield_gc(p41, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc 72>) -guard_isnull(p254, descr=<Guard304>) [p1, p0, p41, p253, p199, p254, p197, p3, p5, p33, p10, p11, p12, p13, p14] -i255 = ptr_eq(p199, p0) -guard_false(i255, descr=<Guard305>) [p1, p0, p41, p253, p199, p197, p3, p5, p33, p10, p11, p12, p13, p14] -i256 = getfield_gc(p41, descr=<NonGcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc 40>) -setfield_gc(p199, ConstPtr(ptr257), descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_last_exception 88>) -i258 = int_is_true(i256) -guard_false(i258, descr=<Guard306>) [p1, p0, p253, p199, p41, p197, p3, p5, p33, p10, p11, p12, p13, p14] -p259 = getfield_gc(p199, descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_f_backref 48>) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #64 STORE_FAST', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #67 LOAD_FAST', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #70 LOAD_CONST', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #73 INPLACE_ADD', 0) -i261 = int_add(i26, 1) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #74 STORE_FAST', 0) -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #77 JUMP_ABSOLUTE', 0) -i263 = getfield_raw(38968960, descr=<SignedFieldDescr pypysig_long_struct.c_value 0>) -i265 = int_sub(i263, 100) -setfield_raw(38968960, i265, descr=<SignedFieldDescr pypysig_long_struct.c_value 0>) -setfield_gc(p41, p259, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref 56>) -setfield_gc(p197, p199, descr=<GcPtrFieldDescr JitVirtualRef.forced 16>) -setfield_gc(p197, -3, descr=<SignedFieldDescr JitVirtualRef.virtual_token 8>) -i268 = int_lt(i265, 0) -guard_false(i268, descr=<Guard307>) [p1, p0, p3, p5, p10, p11, p12, p253, i261] -debug_merge_point('<code object laplace_solve, file '/home/alex/projects/hack/benchmarks/laplace/laplace.py', line 52> #21 LOAD_FAST', 0) -jump(p0, p1, p3, p5, p10, p11, p12, p253, i261, f20, i23, i256, p41, p259, descr=<Loop2>) -[5ed74ff695c8] jit-log-opt-loop} -[5ed8737e9776] {jit-backend-counts -0:493724565 -1:2281802 -2:1283242 -3:993105 -4:2933 -5:2163 -6:2492 -7:1799 -8:963 -9:36 -[5ed8737ee19c] jit-backend-counts} diff --git a/tests/examplefiles/test.r3 b/tests/examplefiles/test.r3 index cad12a8d..707102db 100644 --- a/tests/examplefiles/test.r3 +++ b/tests/examplefiles/test.r3 @@ -1,3 +1,9 @@ +preface.... everything what is before header is not evaluated +so this should not be colorized: +1 + 2 + +REBOL [] ;<- this is minimal header, everything behind it must be colorized + ;## String tests ## print "Hello ^"World" ;<- with escaped char multiline-string: { @@ -52,15 +58,29 @@ type? #ff0000 ;== issue! to integer! (1 + (x / 4.5) * 1E-4) ;## some spec comments -comment now -comment 10 +1 + 1 +comment "aa" +2 + 2 +comment {aa} +3 + 3 +comment {a^{} +4 + 4 +comment {{}} +5 + 5 comment { - bla - bla + foo: 6 } -comment [ - quit -] +6 + 6 +comment [foo: 6] +7 + 7 +comment [foo: "[" ] +8 + 8 +comment [foo: {^{} ] +9 + 9 +comment [foo: {boo} ] +10 + 10 +comment 5-May-2014/11:17:34+2:00 +5-May-2014/11:17:34+2:00 11 + 11 ;## other tests ## ---: 1 diff --git a/tests/examplefiles/test.rsl b/tests/examplefiles/test.rsl new file mode 100644 index 00000000..d6c9fc9a --- /dev/null +++ b/tests/examplefiles/test.rsl @@ -0,0 +1,111 @@ +scheme COMPILER = +class + type + Prog == mk_Prog(stmt : Stmt), + + Stmt == + mk_Asgn(ide : Identifier, expr : Expr) | + mk_If(cond : Expr, s1 : Stmt, s2 : Stmt) | + mk_Seq(head : Stmt, last : Stmt), + + Expr == + mk_Const(const : Int) | + mk_Plus(fst : Expr, snd : Expr) | + mk_Id(ide : Identifier), + Identifier = Text + +type /* storage for program variables */ + `Sigma = Identifier -m-> Int + +value + m : Prog -> `Sigma -> `Sigma + m(p)(`sigma) is m(stmt(p))(`sigma), + + m : Stmt -> `Sigma -> `Sigma + m(s)(`sigma) is + case s of + mk_Asgn(i, e) -> `sigma !! [i +> m(e)(`sigma)], + mk_Seq(s1, s2) -> m(s2)(m(s1)(`sigma)), + mk_If(c, s1, s2) -> + if m(c)(`sigma) ~= 0 then m(s1)(`sigma) else m(s2)(`sigma) end + end, + + m : Expr -> `Sigma -> Int + m(e)(`sigma) is + case e of + mk_Const(n) -> n, + mk_Plus(e1, e2) -> m(e1)(`sigma) + m(e2)(`sigma), + mk_Id(id) -> if id isin dom `sigma then `sigma(id) else 0 end + end + +type + MProg = Inst-list, + Inst == + mk_Push(ide1 : Identifier) | + mk_Pop(Unit) | + mk_Add(Unit) | + mk_Cnst(val : Int) | + mk_Store(ide2 : Identifier) | + mk_Jumpfalse(off1 : Int) | + mk_Jump(off2 : Int) + + +/* An interpreter for SMALL instructions */ + +type Stack = Int-list +value + I : MProg >< Int >< Stack -> (`Sigma ->`Sigma) + I(mp, pc, s)(`sigma) is + if pc <= 0 \/ pc > len mp then `sigma else + case mp(pc) of + mk_Push(x) -> if x isin dom `sigma + then I(mp, pc + 1, <.`sigma(x).> ^ s)(`sigma) + else I(mp, pc + 1, <.0.> ^ s)(`sigma) end, + mk_Pop(()) -> if len s = 0 then `sigma + else I(mp, pc + 1, tl s)(`sigma) end, + mk_Cnst(n) -> I(mp, pc + 1, <.n.> ^ s)(`sigma), + mk_Add(()) -> if len s < 2 then `sigma + else I(mp, pc + 1,<.s(1) + s(2).> ^ tl tl s)(`sigma) end, + mk_Store(x) -> if len s = 0 then `sigma + else I(mp, pc + 1, s)(`sigma !! [x +> s(1)]) end, + mk_Jumpfalse(n) -> if len s = 0 then `sigma + elsif hd s ~= 0 then I(mp, pc + 1, s)(`sigma) + else I(mp, pc + n, s)(`sigma) end, + mk_Jump(n) -> I(mp, pc + n, s)(`sigma) + end + end + +value + comp_Prog : Prog -> MProg + comp_Prog(p) is comp_Stmt(stmt(p)), + + comp_Stmt : Stmt -> MProg + comp_Stmt(s) is + case s of + mk_Asgn(id, e) -> comp_Expr(e) ^ <. mk_Store(id), mk_Pop() .>, + mk_Seq(s1, s2) -> comp_Stmt(s1) ^ comp_Stmt(s2), + mk_If(e, s1, s2) -> + let + ce = comp_Expr(e), + cs1 = comp_Stmt(s1), cs2 = comp_Stmt(s2) + in + ce ^ + <. mk_Jumpfalse(len cs1 + 3) .> ^ + <. mk_Pop() .> ^ + cs1 ^ + <. mk_Jump(len cs2 + 2) .> ^ + <. mk_Pop() .> ^ + cs2 + end + end, + + comp_Expr : Expr -> MProg + comp_Expr(e) is + case e of + mk_Const(n) -> <. mk_Cnst(n) .>, + mk_Plus(e1, e2) -> + comp_Expr(e1) ^ comp_Expr(e2) ^ <. mk_Add() .>, + mk_Id(id) -> <. mk_Push(id) .> + end + +end diff --git a/tests/examplefiles/test.swift b/tests/examplefiles/test.swift new file mode 100644 index 00000000..8ef19763 --- /dev/null +++ b/tests/examplefiles/test.swift @@ -0,0 +1,65 @@ +// +// test.swift +// from https://github.com/fullstackio/FlappySwift +// +// Created by Nate Murray on 6/2/14. +// Copyright (c) 2014 Fullstack.io. All rights reserved. +// + +import UIKit +import SpriteKit + +extension SKNode { + class func unarchiveFromFile(file : NSString) -> SKNode? { + + let path = NSBundle.mainBundle().pathForResource(file, ofType: "sks") + + var sceneData = NSData.dataWithContentsOfFile(path, options: .DataReadingMappedIfSafe, error: nil) + var archiver = NSKeyedUnarchiver(forReadingWithData: sceneData) + + archiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKScene") + let scene = archiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as GameScene + archiver.finishDecoding() + return scene + } +} + +class GameViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene { + // Configure the view. + let skView = self.view as SKView + skView.showsFPS = true + skView.showsNodeCount = true + + /* Sprite Kit applies additional optimizations to improve rendering performance */ + skView.ignoresSiblingOrder = true + + /* Set the scale mode to scale to fit the window */ + scene.scaleMode = .AspectFill + + skView.presentScene(scene) + } + } + + override func shouldAutorotate() -> Bool { + return true + } + + override func supportedInterfaceOrientations() -> Int { + if UIDevice.currentDevice().userInterfaceIdiom == .Phone { + return Int(UIInterfaceOrientationMask.AllButUpsideDown.toRaw()) + } else { + return Int(UIInterfaceOrientationMask.All.toRaw()) + } + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Release any cached data, images, etc that aren't in use. + } + +} diff --git a/tests/examplefiles/test.zep b/tests/examplefiles/test.zep new file mode 100644 index 00000000..4724d4c4 --- /dev/null +++ b/tests/examplefiles/test.zep @@ -0,0 +1,33 @@ +namespace Test; + +use Test\Foo; + +class Bar +{ + protected a; + private b; + public c {set, get}; + + public function __construct(string str, boolean bool) + { + let this->c = str; + this->setC(bool); + let this->b = []; + } + + public function sayHello(string name) + { + echo "Hello " . name; + } + + protected function loops() + { + for a in b { + echo a; + } + loop { + return "boo!"; + } + } + +}
\ No newline at end of file diff --git a/tests/examplefiles/twig_test b/tests/examplefiles/twig_test new file mode 100644 index 00000000..0932fe90 --- /dev/null +++ b/tests/examplefiles/twig_test @@ -0,0 +1,4612 @@ +From the Twig test suite, https://github.com/fabpot/Twig, available under BSD license. + +--TEST-- +Exception for an unclosed tag +--TEMPLATE-- +{% block foo %} + {% if foo %} + + + + + {% for i in fo %} + + + + {% endfor %} + + + +{% endblock %} +--EXCEPTION-- +Twig_Error_Syntax: Unexpected tag name "endblock" (expecting closing tag for the "if" tag defined near line 4) in "index.twig" at line 16 +--TEST-- +Exception for an undefined trait +--TEMPLATE-- +{% use 'foo' with foobar as bar %} +--TEMPLATE(foo)-- +{% block bar %} +{% endblock %} +--EXCEPTION-- +Twig_Error_Runtime: Block "foobar" is not defined in trait "foo" in "index.twig". +--TEST-- +Twig supports method calls +--TEMPLATE-- +{{ items.foo }} +{{ items['foo'] }} +{{ items[foo] }} +{{ items[items[foo]] }} +--DATA-- +return array('foo' => 'bar', 'items' => array('foo' => 'bar', 'bar' => 'foo')) +--EXPECT-- +bar +bar +foo +bar +--TEST-- +Twig supports array notation +--TEMPLATE-- +{# empty array #} +{{ []|join(',') }} + +{{ [1, 2]|join(',') }} +{{ ['foo', "bar"]|join(',') }} +{{ {0: 1, 'foo': 'bar'}|join(',') }} +{{ {0: 1, 'foo': 'bar'}|keys|join(',') }} + +{{ {0: 1, foo: 'bar'}|join(',') }} +{{ {0: 1, foo: 'bar'}|keys|join(',') }} + +{# nested arrays #} +{% set a = [1, 2, [1, 2], {'foo': {'foo': 'bar'}}] %} +{{ a[2]|join(',') }} +{{ a[3]["foo"]|join(',') }} + +{# works even if [] is used inside the array #} +{{ [foo[bar]]|join(',') }} + +{# elements can be any expression #} +{{ ['foo'|upper, bar|upper, bar == foo]|join(',') }} + +{# arrays can have a trailing , like in PHP #} +{{ + [ + 1, + 2, + ]|join(',') +}} + +{# keys can be any expression #} +{% set a = 1 %} +{% set b = "foo" %} +{% set ary = { (a): 'a', (b): 'b', 'c': 'c', (a ~ b): 'd' } %} +{{ ary|keys|join(',') }} +{{ ary|join(',') }} +--DATA-- +return array('bar' => 'bar', 'foo' => array('bar' => 'bar')) +--EXPECT-- +1,2 +foo,bar +1,bar +0,foo + +1,bar +0,foo + +1,2 +bar + +bar + +FOO,BAR, + +1,2 + +1,foo,c,1foo +a,b,c,d +--TEST-- +Twig supports binary operations (+, -, *, /, ~, %, and, or) +--TEMPLATE-- +{{ 1 + 1 }} +{{ 2 - 1 }} +{{ 2 * 2 }} +{{ 2 / 2 }} +{{ 3 % 2 }} +{{ 1 and 1 }} +{{ 1 and 0 }} +{{ 0 and 1 }} +{{ 0 and 0 }} +{{ 1 or 1 }} +{{ 1 or 0 }} +{{ 0 or 1 }} +{{ 0 or 0 }} +{{ 0 or 1 and 0 }} +{{ 1 or 0 and 1 }} +{{ "foo" ~ "bar" }} +{{ foo ~ "bar" }} +{{ "foo" ~ bar }} +{{ foo ~ bar }} +{{ 20 // 7 }} +--DATA-- +return array('foo' => 'bar', 'bar' => 'foo') +--EXPECT-- +2 +1 +4 +1 +1 +1 + + + +1 +1 +1 + + +1 +foobar +barbar +foofoo +barfoo +2 +--TEST-- +Twig supports bitwise operations +--TEMPLATE-- +{{ 1 b-and 5 }} +{{ 1 b-or 5 }} +{{ 1 b-xor 5 }} +{{ (1 and 0 b-or 0) is same as(1 and (0 b-or 0)) ? 'ok' : 'ko' }} +--DATA-- +return array() +--EXPECT-- +1 +5 +4 +ok +--TEST-- +Twig supports comparison operators (==, !=, <, >, >=, <=) +--TEMPLATE-- +{{ 1 > 2 }}/{{ 1 > 1 }}/{{ 1 >= 2 }}/{{ 1 >= 1 }} +{{ 1 < 2 }}/{{ 1 < 1 }}/{{ 1 <= 2 }}/{{ 1 <= 1 }} +{{ 1 == 1 }}/{{ 1 == 2 }} +{{ 1 != 1 }}/{{ 1 != 2 }} +--DATA-- +return array() +--EXPECT-- +///1 +1//1/1 +1/ +/1 +--TEST-- +Twig supports the "divisible by" operator +--TEMPLATE-- +{{ 8 is divisible by(2) ? 'OK' }} +{{ 8 is not divisible by(3) ? 'OK' }} +{{ 8 is divisible by (2) ? 'OK' }} +{{ 8 is not + divisible + by + (3) ? 'OK' }} +--DATA-- +return array() +--EXPECT-- +OK +OK +OK +OK +--TEST-- +Twig supports the .. operator +--TEMPLATE-- +{% for i in 0..10 %}{{ i }} {% endfor %} + +{% for letter in 'a'..'z' %}{{ letter }} {% endfor %} + +{% for letter in 'a'|upper..'z'|upper %}{{ letter }} {% endfor %} + +{% for i in foo[0]..foo[1] %}{{ i }} {% endfor %} + +{% for i in 0 + 1 .. 10 - 1 %}{{ i }} {% endfor %} +--DATA-- +return array('foo' => array(1, 10)) +--EXPECT-- +0 1 2 3 4 5 6 7 8 9 10 +a b c d e f g h i j k l m n o p q r s t u v w x y z +A B C D E F G H I J K L M N O P Q R S T U V W X Y Z +1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 +--TEST-- +Twig supports the "ends with" operator +--TEMPLATE-- +{{ 'foo' ends with 'o' ? 'OK' : 'KO' }} +{{ not ('foo' ends with 'f') ? 'OK' : 'KO' }} +{{ not ('foo' ends with 'foowaytoolong') ? 'OK' : 'KO' }} +{{ 'foo' ends with '' ? 'OK' : 'KO' }} +{{ '1' ends with true ? 'OK' : 'KO' }} +{{ 1 ends with true ? 'OK' : 'KO' }} +{{ 0 ends with false ? 'OK' : 'KO' }} +{{ '' ends with false ? 'OK' : 'KO' }} +{{ false ends with false ? 'OK' : 'KO' }} +{{ false ends with '' ? 'OK' : 'KO' }} +--DATA-- +return array() +--EXPECT-- +OK +OK +OK +OK +KO +KO +KO +KO +KO +KO +--TEST-- +Twig supports grouping of expressions +--TEMPLATE-- +{{ (2 + 2) / 2 }} +--DATA-- +return array() +--EXPECT-- +2 +--TEST-- +Twig supports literals +--TEMPLATE-- +1 {{ true }} +2 {{ TRUE }} +3 {{ false }} +4 {{ FALSE }} +5 {{ none }} +6 {{ NONE }} +7 {{ null }} +8 {{ NULL }} +--DATA-- +return array() +--EXPECT-- +1 1 +2 1 +3 +4 +5 +6 +7 +8 +--TEST-- +Twig supports __call() for attributes +--TEMPLATE-- +{{ foo.foo }} +{{ foo.bar }} +--EXPECT-- +foo_from_call +bar_from_getbar +--TEST-- +Twig supports the "matches" operator +--TEMPLATE-- +{{ 'foo' matches '/o/' ? 'OK' : 'KO' }} +{{ 'foo' matches '/^fo/' ? 'OK' : 'KO' }} +{{ 'foo' matches '/O/i' ? 'OK' : 'KO' }} +--DATA-- +return array() +--EXPECT-- +OK +OK +OK +--TEST-- +Twig supports method calls +--TEMPLATE-- +{{ items.foo.foo }} +{{ items.foo.getFoo() }} +{{ items.foo.bar }} +{{ items.foo['bar'] }} +{{ items.foo.bar('a', 43) }} +{{ items.foo.bar(foo) }} +{{ items.foo.self.foo() }} +{{ items.foo.is }} +{{ items.foo.in }} +{{ items.foo.not }} +--DATA-- +return array('foo' => 'bar', 'items' => array('foo' => new TwigTestFoo(), 'bar' => 'foo')) +--CONFIG-- +return array('strict_variables' => false) +--EXPECT-- +foo +foo +bar + +bar_a-43 +bar_bar +foo +is +in +not +--TEST-- +Twig allows to use named operators as variable names +--TEMPLATE-- +{% for match in matches %} + {{- match }} +{% endfor %} +{{ in }} +{{ is }} +--DATA-- +return array('matches' => array(1, 2, 3), 'in' => 'in', 'is' => 'is') +--EXPECT-- +1 +2 +3 +in +is +--TEST-- +Twig parses postfix expressions +--TEMPLATE-- +{% import _self as macros %} + +{% macro foo() %}foo{% endmacro %} + +{{ 'a' }} +{{ 'a'|upper }} +{{ ('a')|upper }} +{{ -1|upper }} +{{ macros.foo() }} +{{ (macros).foo() }} +--DATA-- +return array(); +--EXPECT-- +a +A +A +-1 +foo +foo +--TEST-- +Twig supports the "same as" operator +--TEMPLATE-- +{{ 1 is same as(1) ? 'OK' }} +{{ 1 is not same as(true) ? 'OK' }} +{{ 1 is same as(1) ? 'OK' }} +{{ 1 is not same as(true) ? 'OK' }} +{{ 1 is same as (1) ? 'OK' }} +{{ 1 is not + same + as + (true) ? 'OK' }} +--DATA-- +return array() +--EXPECT-- +OK +OK +OK +OK +OK +OK +--TEST-- +Twig supports the "starts with" operator +--TEMPLATE-- +{{ 'foo' starts with 'f' ? 'OK' : 'KO' }} +{{ not ('foo' starts with 'oo') ? 'OK' : 'KO' }} +{{ not ('foo' starts with 'foowaytoolong') ? 'OK' : 'KO' }} +{{ 'foo' starts with 'f' ? 'OK' : 'KO' }} +{{ 'foo' starts +with 'f' ? 'OK' : 'KO' }} +{{ 'foo' starts with '' ? 'OK' : 'KO' }} +{{ '1' starts with true ? 'OK' : 'KO' }} +{{ '' starts with false ? 'OK' : 'KO' }} +{{ 'a' starts with false ? 'OK' : 'KO' }} +{{ false starts with '' ? 'OK' : 'KO' }} +--DATA-- +return array() +--EXPECT-- +OK +OK +OK +OK +OK +OK +KO +KO +KO +KO +--TEST-- +Twig supports string interpolation +--TEMPLATE-- +{# "foo #{"foo #{bar} baz"} baz" #} +{# "foo #{bar}#{bar} baz" #} +--DATA-- +return array('bar' => 'BAR'); +--EXPECT-- +foo foo BAR baz baz +foo BARBAR baz +--TEST-- +Twig supports the ternary operator +--TEMPLATE-- +{{ 1 ? 'YES' }} +{{ 0 ? 'YES' }} +--DATA-- +return array() +--EXPECT-- +YES + +--TEST-- +Twig supports the ternary operator +--TEMPLATE-- +{{ 'YES' ?: 'NO' }} +{{ 0 ?: 'NO' }} +--DATA-- +return array() +--EXPECT-- +YES +NO +--TEST-- +Twig supports the ternary operator +--TEMPLATE-- +{{ 1 ? 'YES' : 'NO' }} +{{ 0 ? 'YES' : 'NO' }} +{{ 0 ? 'YES' : (1 ? 'YES1' : 'NO1') }} +{{ 0 ? 'YES' : (0 ? 'YES1' : 'NO1') }} +{{ 1 == 1 ? 'foo<br />':'' }} +{{ foo ~ (bar ? ('-' ~ bar) : '') }} +--DATA-- +return array('foo' => 'foo', 'bar' => 'bar') +--EXPECT-- +YES +NO +YES1 +NO1 +foo<br /> +foo-bar +--TEST-- +Twig does not allow to use two-word named operators as variable names +--TEMPLATE-- +{{ starts with }} +--DATA-- +return array() +--EXCEPTION-- +Twig_Error_Syntax: Unexpected token "operator" of value "starts with" in "index.twig" at line 2 +--TEST-- +Twig unary operators precedence +--TEMPLATE-- +{{ -1 - 1 }} +{{ -1 - -1 }} +{{ -1 * -1 }} +{{ 4 / -1 * 5 }} +--DATA-- +return array() +--EXPECT-- +-2 +0 +1 +-20 +--TEST-- +Twig supports unary operators (not, -, +) +--TEMPLATE-- +{{ not 1 }}/{{ not 0 }} +{{ +1 + 1 }}/{{ -1 - 1 }} +{{ not (false or true) }} +--DATA-- +return array() +--EXPECT-- +/1 +2/-2 + +--TEST-- +"abs" filter +--TEMPLATE-- +{{ (-5.5)|abs }} +{{ (-5)|abs }} +{{ (-0)|abs }} +{{ 0|abs }} +{{ 5|abs }} +{{ 5.5|abs }} +{{ number1|abs }} +{{ number2|abs }} +{{ number3|abs }} +{{ number4|abs }} +{{ number5|abs }} +{{ number6|abs }} +--DATA-- +return array('number1' => -5.5, 'number2' => -5, 'number3' => -0, 'number4' => 0, 'number5' => 5, 'number6' => 5.5) +--EXPECT-- +5.5 +5 +0 +0 +5 +5.5 +5.5 +5 +0 +0 +5 +5.5 +--TEST-- +"batch" filter +--TEMPLATE-- +{% for row in items|batch(3.1) %} + <div class=row> + {% for column in row %} + <div class=item>{{ column }}</div> + {% endfor %} + </div> +{% endfor %} +--DATA-- +return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j')) +--EXPECT-- +<div class=row> + <div class=item>a</div> + <div class=item>b</div> + <div class=item>c</div> + <div class=item>d</div> + </div> + <div class=row> + <div class=item>e</div> + <div class=item>f</div> + <div class=item>g</div> + <div class=item>h</div> + </div> + <div class=row> + <div class=item>i</div> + <div class=item>j</div> + </div> +--TEST-- +"batch" filter +--TEMPLATE-- +{% for row in items|batch(3) %} + <div class=row> + {% for column in row %} + <div class=item>{{ column }}</div> + {% endfor %} + </div> +{% endfor %} +--DATA-- +return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j')) +--EXPECT-- +<div class=row> + <div class=item>a</div> + <div class=item>b</div> + <div class=item>c</div> + </div> + <div class=row> + <div class=item>d</div> + <div class=item>e</div> + <div class=item>f</div> + </div> + <div class=row> + <div class=item>g</div> + <div class=item>h</div> + <div class=item>i</div> + </div> + <div class=row> + <div class=item>j</div> + </div> +--TEST-- +"batch" filter +--TEMPLATE-- +<table> +{% for row in items|batch(3, '') %} + <tr> + {% for column in row %} + <td>{{ column }}</td> + {% endfor %} + </tr> +{% endfor %} +</table> +--DATA-- +return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j')) +--EXPECT-- +<table> + <tr> + <td>a</td> + <td>b</td> + <td>c</td> + </tr> + <tr> + <td>d</td> + <td>e</td> + <td>f</td> + </tr> + <tr> + <td>g</td> + <td>h</td> + <td>i</td> + </tr> + <tr> + <td>j</td> + <td></td> + <td></td> + </tr> +</table> +--TEST-- +"batch" filter +--TEMPLATE-- +{% for row in items|batch(3, 'fill') %} + <div class=row> + {% for column in row %} + <div class=item>{{ column }}</div> + {% endfor %} + </div> +{% endfor %} +--DATA-- +return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l')) +--EXPECT-- +<div class=row> + <div class=item>a</div> + <div class=item>b</div> + <div class=item>c</div> + </div> + <div class=row> + <div class=item>d</div> + <div class=item>e</div> + <div class=item>f</div> + </div> + <div class=row> + <div class=item>g</div> + <div class=item>h</div> + <div class=item>i</div> + </div> + <div class=row> + <div class=item>j</div> + <div class=item>k</div> + <div class=item>l</div> + </div> +--TEST-- +"batch" filter +--TEMPLATE-- +<table> +{% for row in items|batch(3, 'fill') %} + <tr> + {% for column in row %} + <td>{{ column }}</td> + {% endfor %} + </tr> +{% endfor %} +</table> +--DATA-- +return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j')) +--EXPECT-- +<table> + <tr> + <td>a</td> + <td>b</td> + <td>c</td> + </tr> + <tr> + <td>d</td> + <td>e</td> + <td>f</td> + </tr> + <tr> + <td>g</td> + <td>h</td> + <td>i</td> + </tr> + <tr> + <td>j</td> + <td>fill</td> + <td>fill</td> + </tr> +</table> +--TEST-- +"convert_encoding" filter +--CONDITION-- +function_exists('iconv') || function_exists('mb_convert_encoding') +--TEMPLATE-- +{{ "愛していますか?"|convert_encoding('ISO-2022-JP', 'UTF-8')|convert_encoding('UTF-8', 'ISO-2022-JP') }} +--DATA-- +return array() +--EXPECT-- +愛していますか? +--TEST-- +"date" filter (interval support as of PHP 5.3) +--CONDITION-- +version_compare(phpversion(), '5.3.0', '>=') +--TEMPLATE-- +{{ date2|date }} +{{ date2|date('%d days') }} +--DATA-- +date_default_timezone_set('UTC'); +$twig->getExtension('core')->setDateFormat('Y-m-d', '%d days %h hours'); +return array( + 'date2' => new DateInterval('P2D'), +) +--EXPECT-- +2 days 0 hours +2 days +--TEST-- +"date" filter +--TEMPLATE-- +{{ date1|date }} +{{ date1|date('d/m/Y') }} +--DATA-- +date_default_timezone_set('UTC'); +$twig->getExtension('core')->setDateFormat('Y-m-d', '%d days %h hours'); +return array( + 'date1' => mktime(13, 45, 0, 10, 4, 2010), +) +--EXPECT-- +2010-10-04 +04/10/2010 +--TEST-- +"date" filter +--CONDITION-- +version_compare(phpversion(), '5.5.0', '>=') +--TEMPLATE-- +{{ date1|date }} +{{ date1|date('d/m/Y') }} +{{ date1|date('d/m/Y H:i:s', 'Asia/Hong_Kong') }} +{{ date1|date('d/m/Y H:i:s', timezone1) }} +{{ date1|date('d/m/Y H:i:s') }} + +{{ date2|date('d/m/Y H:i:s P', 'Europe/Paris') }} +{{ date2|date('d/m/Y H:i:s P', 'Asia/Hong_Kong') }} +{{ date2|date('d/m/Y H:i:s P', false) }} +{{ date2|date('e', 'Europe/Paris') }} +{{ date2|date('e', false) }} +--DATA-- +date_default_timezone_set('Europe/Paris'); +return array( + 'date1' => new DateTimeImmutable('2010-10-04 13:45'), + 'date2' => new DateTimeImmutable('2010-10-04 13:45', new DateTimeZone('America/New_York')), + 'timezone1' => new DateTimeZone('America/New_York'), +) +--EXPECT-- +October 4, 2010 13:45 +04/10/2010 +04/10/2010 19:45:00 +04/10/2010 07:45:00 +04/10/2010 13:45:00 + +04/10/2010 19:45:00 +02:00 +05/10/2010 01:45:00 +08:00 +04/10/2010 13:45:00 -04:00 +Europe/Paris +America/New_York +--TEST-- +"date" filter (interval support as of PHP 5.3) +--CONDITION-- +version_compare(phpversion(), '5.3.0', '>=') +--TEMPLATE-- +{{ date1|date }} +{{ date1|date('%d days %h hours') }} +{{ date1|date('%d days %h hours', timezone1) }} +--DATA-- +date_default_timezone_set('UTC'); +return array( + 'date1' => new DateInterval('P2D'), + // This should have no effect on DateInterval formatting + 'timezone1' => new DateTimeZone('America/New_York'), +) +--EXPECT-- +2 days +2 days 0 hours +2 days 0 hours +--TEST-- +"date_modify" filter +--TEMPLATE-- +{{ date1|date_modify('-1day')|date('Y-m-d H:i:s') }} +{{ date2|date_modify('-1day')|date('Y-m-d H:i:s') }} +--DATA-- +date_default_timezone_set('UTC'); +return array( + 'date1' => '2010-10-04 13:45', + 'date2' => new DateTime('2010-10-04 13:45'), +) +--EXPECT-- +2010-10-03 13:45:00 +2010-10-03 13:45:00 +--TEST-- +"date" filter +--TEMPLATE-- +{{ date|date(format='d/m/Y H:i:s P', timezone='America/Chicago') }} +{{ date|date(timezone='America/Chicago', format='d/m/Y H:i:s P') }} +{{ date|date('d/m/Y H:i:s P', timezone='America/Chicago') }} +--DATA-- +date_default_timezone_set('UTC'); +return array('date' => mktime(13, 45, 0, 10, 4, 2010)) +--EXPECT-- +04/10/2010 08:45:00 -05:00 +04/10/2010 08:45:00 -05:00 +04/10/2010 08:45:00 -05:00 +--TEST-- +"date" filter +--TEMPLATE-- +{{ date1|date }} +{{ date1|date('d/m/Y') }} +{{ date1|date('d/m/Y H:i:s', 'Asia/Hong_Kong') }} +{{ date1|date('d/m/Y H:i:s P', 'Asia/Hong_Kong') }} +{{ date1|date('d/m/Y H:i:s P', 'America/Chicago') }} +{{ date1|date('e') }} +{{ date1|date('d/m/Y H:i:s') }} + +{{ date2|date }} +{{ date2|date('d/m/Y') }} +{{ date2|date('d/m/Y H:i:s', 'Asia/Hong_Kong') }} +{{ date2|date('d/m/Y H:i:s', timezone1) }} +{{ date2|date('d/m/Y H:i:s') }} + +{{ date3|date }} +{{ date3|date('d/m/Y') }} + +{{ date4|date }} +{{ date4|date('d/m/Y') }} + +{{ date5|date }} +{{ date5|date('d/m/Y') }} + +{{ date6|date('d/m/Y H:i:s P', 'Europe/Paris') }} +{{ date6|date('d/m/Y H:i:s P', 'Asia/Hong_Kong') }} +{{ date6|date('d/m/Y H:i:s P', false) }} +{{ date6|date('e', 'Europe/Paris') }} +{{ date6|date('e', false) }} + +{{ date7|date }} +--DATA-- +date_default_timezone_set('Europe/Paris'); +return array( + 'date1' => mktime(13, 45, 0, 10, 4, 2010), + 'date2' => new DateTime('2010-10-04 13:45'), + 'date3' => '2010-10-04 13:45', + 'date4' => 1286199900, // DateTime::createFromFormat('Y-m-d H:i', '2010-10-04 13:45', new DateTimeZone('UTC'))->getTimestamp() -- A unixtimestamp is always GMT + 'date5' => -189291360, // DateTime::createFromFormat('Y-m-d H:i', '1964-01-02 03:04', new DateTimeZone('UTC'))->getTimestamp(), + 'date6' => new DateTime('2010-10-04 13:45', new DateTimeZone('America/New_York')), + 'date7' => '2010-01-28T15:00:00+05:00', + 'timezone1' => new DateTimeZone('America/New_York'), +) +--EXPECT-- +October 4, 2010 13:45 +04/10/2010 +04/10/2010 19:45:00 +04/10/2010 19:45:00 +08:00 +04/10/2010 06:45:00 -05:00 +Europe/Paris +04/10/2010 13:45:00 + +October 4, 2010 13:45 +04/10/2010 +04/10/2010 19:45:00 +04/10/2010 07:45:00 +04/10/2010 13:45:00 + +October 4, 2010 13:45 +04/10/2010 + +October 4, 2010 15:45 +04/10/2010 + +January 2, 1964 04:04 +02/01/1964 + +04/10/2010 19:45:00 +02:00 +05/10/2010 01:45:00 +08:00 +04/10/2010 13:45:00 -04:00 +Europe/Paris +America/New_York + +January 28, 2010 11:00 +--TEST-- +"default" filter +--TEMPLATE-- +Variable: +{{ definedVar |default('default') is same as('default') ? 'ko' : 'ok' }} +{{ zeroVar |default('default') is same as('default') ? 'ko' : 'ok' }} +{{ emptyVar |default('default') is same as('default') ? 'ok' : 'ko' }} +{{ nullVar |default('default') is same as('default') ? 'ok' : 'ko' }} +{{ undefinedVar |default('default') is same as('default') ? 'ok' : 'ko' }} +Array access: +{{ nested.definedVar |default('default') is same as('default') ? 'ko' : 'ok' }} +{{ nested['definedVar'] |default('default') is same as('default') ? 'ko' : 'ok' }} +{{ nested.zeroVar |default('default') is same as('default') ? 'ko' : 'ok' }} +{{ nested.emptyVar |default('default') is same as('default') ? 'ok' : 'ko' }} +{{ nested.nullVar |default('default') is same as('default') ? 'ok' : 'ko' }} +{{ nested.undefinedVar |default('default') is same as('default') ? 'ok' : 'ko' }} +{{ nested['undefinedVar'] |default('default') is same as('default') ? 'ok' : 'ko' }} +{{ undefinedVar.foo |default('default') is same as('default') ? 'ok' : 'ko' }} +Plain values: +{{ 'defined' |default('default') is same as('default') ? 'ko' : 'ok' }} +{{ 0 |default('default') is same as('default') ? 'ko' : 'ok' }} +{{ '' |default('default') is same as('default') ? 'ok' : 'ko' }} +{{ null |default('default') is same as('default') ? 'ok' : 'ko' }} +Precedence: +{{ 'o' ~ nullVar |default('k') }} +{{ 'o' ~ nested.nullVar |default('k') }} +Object methods: +{{ object.foo |default('default') is same as('default') ? 'ko' : 'ok' }} +{{ object.undefinedMethod |default('default') is same as('default') ? 'ok' : 'ko' }} +{{ object.getFoo() |default('default') is same as('default') ? 'ko' : 'ok' }} +{{ object.getFoo('a') |default('default') is same as('default') ? 'ko' : 'ok' }} +{{ object.undefinedMethod() |default('default') is same as('default') ? 'ok' : 'ko' }} +{{ object.undefinedMethod('a') |default('default') is same as('default') ? 'ok' : 'ko' }} +Deep nested: +{{ nested.undefinedVar.foo.bar |default('default') is same as('default') ? 'ok' : 'ko' }} +{{ nested.definedArray.0 |default('default') is same as('default') ? 'ko' : 'ok' }} +{{ nested['definedArray'][0] |default('default') is same as('default') ? 'ko' : 'ok' }} +{{ object.self.foo |default('default') is same as('default') ? 'ko' : 'ok' }} +{{ object.self.undefinedMethod |default('default') is same as('default') ? 'ok' : 'ko' }} +{{ object.undefinedMethod.self |default('default') is same as('default') ? 'ok' : 'ko' }} +--DATA-- +return array( + 'definedVar' => 'defined', + 'zeroVar' => 0, + 'emptyVar' => '', + 'nullVar' => null, + 'nested' => array( + 'definedVar' => 'defined', + 'zeroVar' => 0, + 'emptyVar' => '', + 'nullVar' => null, + 'definedArray' => array(0), + ), + 'object' => new TwigTestFoo(), +) +--CONFIG-- +return array('strict_variables' => false) +--EXPECT-- +Variable: +ok +ok +ok +ok +ok +Array access: +ok +ok +ok +ok +ok +ok +ok +ok +Plain values: +ok +ok +ok +ok +Precedence: +ok +ok +Object methods: +ok +ok +ok +ok +ok +ok +Deep nested: +ok +ok +ok +ok +ok +ok +--DATA-- +return array( + 'definedVar' => 'defined', + 'zeroVar' => 0, + 'emptyVar' => '', + 'nullVar' => null, + 'nested' => array( + 'definedVar' => 'defined', + 'zeroVar' => 0, + 'emptyVar' => '', + 'nullVar' => null, + 'definedArray' => array(0), + ), + 'object' => new TwigTestFoo(), +) +--CONFIG-- +return array('strict_variables' => true) +--EXPECT-- +Variable: +ok +ok +ok +ok +ok +Array access: +ok +ok +ok +ok +ok +ok +ok +ok +Plain values: +ok +ok +ok +ok +Precedence: +ok +ok +Object methods: +ok +ok +ok +ok +ok +ok +Deep nested: +ok +ok +ok +ok +ok +ok +--TEST-- +dynamic filter +--TEMPLATE-- +{{ 'bar'|foo_path }} +{{ 'bar'|a_foo_b_bar }} +--DATA-- +return array() +--EXPECT-- +foo/bar +a/b/bar +--TEST-- +"escape" filter does not escape with the html strategy when using the html_attr strategy +--TEMPLATE-- +{{ '<br />'|escape('html_attr') }} +--DATA-- +return array() +--EXPECT-- +<br /> +--TEST-- +"escape" filter +--TEMPLATE-- +{{ "愛していますか? <br />"|e }} +--DATA-- +return array() +--EXPECT-- +愛していますか? <br /> +--TEST-- +"escape" filter +--TEMPLATE-- +{{ "foo <br />"|e }} +--DATA-- +return array() +--EXPECT-- +foo <br /> +--TEST-- +"first" filter +--TEMPLATE-- +{{ [1, 2, 3, 4]|first }} +{{ {a: 1, b: 2, c: 3, d: 4}|first }} +{{ '1234'|first }} +{{ arr|first }} +{{ 'Ä€é'|first }} +{{ ''|first }} +--DATA-- +return array('arr' => new ArrayObject(array(1, 2, 3, 4))) +--EXPECT-- +1 +1 +1 +1 +Ä +--TEST-- +"escape" filter +--TEMPLATE-- +{% set foo %} + foo<br /> +{% endset %} + +{{ foo|e('html') -}} +{{ foo|e('js') }} +{% autoescape true %} + {{ foo }} +{% endautoescape %} +--DATA-- +return array() +--EXPECT-- + foo<br /> +\x20\x20\x20\x20foo\x3Cbr\x20\x2F\x3E\x0A + foo<br /> +--TEST-- +"format" filter +--TEMPLATE-- +{{ string|format(foo, 3) }} +--DATA-- +return array('string' => '%s/%d', 'foo' => 'bar') +--EXPECT-- +bar/3 +--TEST-- +"join" filter +--TEMPLATE-- +{{ ["foo", "bar"]|join(', ') }} +{{ foo|join(', ') }} +{{ bar|join(', ') }} +--DATA-- +return array('foo' => new TwigTestFoo(), 'bar' => new ArrayObject(array(3, 4))) +--EXPECT-- +foo, bar +1, 2 +3, 4 +--TEST-- +"json_encode" filter +--TEMPLATE-- +{{ "foo"|json_encode|raw }} +{{ foo|json_encode|raw }} +{{ [foo, "foo"]|json_encode|raw }} +--DATA-- +return array('foo' => new Twig_Markup('foo', 'UTF-8')) +--EXPECT-- +"foo" +"foo" +["foo","foo"] +--TEST-- +"last" filter +--TEMPLATE-- +{{ [1, 2, 3, 4]|last }} +{{ {a: 1, b: 2, c: 3, d: 4}|last }} +{{ '1234'|last }} +{{ arr|last }} +{{ 'Ä€é'|last }} +{{ ''|last }} +--DATA-- +return array('arr' => new ArrayObject(array(1, 2, 3, 4))) +--EXPECT-- +4 +4 +4 +4 +é +--TEST-- +"length" filter +--TEMPLATE-- +{{ array|length }} +{{ string|length }} +{{ number|length }} +{{ markup|length }} +--DATA-- +return array('array' => array(1, 4), 'string' => 'foo', 'number' => 1000, 'markup' => new Twig_Markup('foo', 'UTF-8')) +--EXPECT-- +2 +3 +4 +3 +--TEST-- +"length" filter +--CONDITION-- +function_exists('mb_get_info') +--TEMPLATE-- +{{ string|length }} +{{ markup|length }} +--DATA-- +return array('string' => 'été', 'markup' => new Twig_Markup('foo', 'UTF-8')) +--EXPECT-- +3 +3 +--TEST-- +"merge" filter +--TEMPLATE-- +{{ items|merge({'bar': 'foo'})|join }} +{{ items|merge({'bar': 'foo'})|keys|join }} +{{ {'bar': 'foo'}|merge(items)|join }} +{{ {'bar': 'foo'}|merge(items)|keys|join }} +{{ numerics|merge([4, 5, 6])|join }} +--DATA-- +return array('items' => array('foo' => 'bar'), 'numerics' => array(1, 2, 3)) +--EXPECT-- +barfoo +foobar +foobar +barfoo +123456 +--TEST-- +"nl2br" filter +--TEMPLATE-- +{{ "I like Twig.\nYou will like it too.\n\nEverybody like it!"|nl2br }} +{{ text|nl2br }} +--DATA-- +return array('text' => "If you have some <strong>HTML</strong>\nit will be escaped.") +--EXPECT-- +I like Twig.<br /> +You will like it too.<br /> +<br /> +Everybody like it! +If you have some <strong>HTML</strong><br /> +it will be escaped. +--TEST-- +"number_format" filter with defaults. +--TEMPLATE-- +{{ 20|number_format }} +{{ 20.25|number_format }} +{{ 20.25|number_format(1) }} +{{ 20.25|number_format(2, ',') }} +{{ 1020.25|number_format }} +{{ 1020.25|number_format(2, ',') }} +{{ 1020.25|number_format(2, ',', '.') }} +--DATA-- +$twig->getExtension('core')->setNumberFormat(2, '!', '='); +return array(); +--EXPECT-- +20!00 +20!25 +20!3 +20,25 +1=020!25 +1=020,25 +1.020,25 +--TEST-- +"number_format" filter +--TEMPLATE-- +{{ 20|number_format }} +{{ 20.25|number_format }} +{{ 20.25|number_format(2) }} +{{ 20.25|number_format(2, ',') }} +{{ 1020.25|number_format(2, ',') }} +{{ 1020.25|number_format(2, ',', '.') }} +--DATA-- +return array(); +--EXPECT-- +20 +20 +20.25 +20,25 +1,020,25 +1.020,25 +--TEST-- +"replace" filter +--TEMPLATE-- +{{ "I like %this% and %that%."|replace({'%this%': "foo", '%that%': "bar"}) }} +--DATA-- +return array() +--EXPECT-- +I like foo and bar. +--TEST-- +"reverse" filter +--TEMPLATE-- +{{ [1, 2, 3, 4]|reverse|join('') }} +{{ '1234évènement'|reverse }} +{{ arr|reverse|join('') }} +{{ {'a': 'c', 'b': 'a'}|reverse()|join(',') }} +{{ {'a': 'c', 'b': 'a'}|reverse(preserveKeys=true)|join(glue=',') }} +{{ {'a': 'c', 'b': 'a'}|reverse(preserve_keys=true)|join(glue=',') }} +--DATA-- +return array('arr' => new ArrayObject(array(1, 2, 3, 4))) +--EXPECT-- +4321 +tnemenèvé4321 +4321 +a,c +a,c +a,c +--TEST-- +"round" filter +--TEMPLATE-- +{{ 2.7|round }} +{{ 2.1|round }} +{{ 2.1234|round(3, 'floor') }} +{{ 2.1|round(0, 'ceil') }} + +{{ 21.3|round(-1)}} +{{ 21.3|round(-1, 'ceil')}} +{{ 21.3|round(-1, 'floor')}} +--DATA-- +return array() +--EXPECT-- +3 +2 +2.123 +3 + +20 +30 +20 +--TEST-- +"slice" filter +--TEMPLATE-- +{{ [1, 2, 3, 4][1:2]|join('') }} +{{ {a: 1, b: 2, c: 3, d: 4}[1:2]|join('') }} +{{ [1, 2, 3, 4][start:length]|join('') }} +{{ [1, 2, 3, 4]|slice(1, 2)|join('') }} +{{ [1, 2, 3, 4]|slice(1, 2)|keys|join('') }} +{{ [1, 2, 3, 4]|slice(1, 2, true)|keys|join('') }} +{{ {a: 1, b: 2, c: 3, d: 4}|slice(1, 2)|join('') }} +{{ {a: 1, b: 2, c: 3, d: 4}|slice(1, 2)|keys|join('') }} +{{ '1234'|slice(1, 2) }} +{{ '1234'[1:2] }} +{{ arr|slice(1, 2)|join('') }} +{{ arr[1:2]|join('') }} + +{{ [1, 2, 3, 4]|slice(1)|join('') }} +{{ [1, 2, 3, 4][1:]|join('') }} +{{ '1234'|slice(1) }} +{{ '1234'[1:] }} +{{ '1234'[:1] }} +--DATA-- +return array('start' => 1, 'length' => 2, 'arr' => new ArrayObject(array(1, 2, 3, 4))) +--EXPECT-- +23 +23 +23 +23 +01 +12 +23 +bc +23 +23 +23 +23 + +234 +234 +234 +234 +1 +--TEST-- +"sort" filter +--TEMPLATE-- +{{ array1|sort|join }} +{{ array2|sort|join }} +--DATA-- +return array('array1' => array(4, 1), 'array2' => array('foo', 'bar')) +--EXPECT-- +14 +barfoo +--TEST-- +"split" filter +--TEMPLATE-- +{{ "one,two,three,four,five"|split(',')|join('-') }} +{{ foo|split(',')|join('-') }} +{{ foo|split(',', 3)|join('-') }} +{{ baz|split('')|join('-') }} +{{ baz|split('', 2)|join('-') }} +{{ foo|split(',', -2)|join('-') }} +--DATA-- +return array('foo' => "one,two,three,four,five", 'baz' => '12345',) +--EXPECT-- +one-two-three-four-five +one-two-three-four-five +one-two-three,four,five +1-2-3-4-5 +12-34-5 +one-two-three--TEST-- +"trim" filter +--TEMPLATE-- +{{ " I like Twig. "|trim }} +{{ text|trim }} +{{ " foo/"|trim("/") }} +--DATA-- +return array('text' => " If you have some <strong>HTML</strong> it will be escaped. ") +--EXPECT-- +I like Twig. +If you have some <strong>HTML</strong> it will be escaped. + foo +--TEST-- +"url_encode" filter for PHP < 5.4 and HHVM +--CONDITION-- +defined('PHP_QUERY_RFC3986') +--TEMPLATE-- +{{ {foo: "bar", number: 3, "spéßi%l": "e%c0d@d", "spa ce": ""}|url_encode }} +{{ {foo: "bar", number: 3, "spéßi%l": "e%c0d@d", "spa ce": ""}|url_encode|raw }} +{{ {}|url_encode|default("default") }} +{{ 'spéßi%le%c0d@dspa ce'|url_encode }} +--DATA-- +return array() +--EXPECT-- +foo=bar&number=3&sp%C3%A9%C3%9Fi%25l=e%25c0d%40d&spa%20ce= +foo=bar&number=3&sp%C3%A9%C3%9Fi%25l=e%25c0d%40d&spa%20ce= +default +sp%C3%A9%C3%9Fi%25le%25c0d%40dspa%20ce +--TEST-- +"url_encode" filter +--CONDITION-- +defined('PHP_QUERY_RFC3986') +--TEMPLATE-- +{{ {foo: "bar", number: 3, "spéßi%l": "e%c0d@d", "spa ce": ""}|url_encode }} +{{ {foo: "bar", number: 3, "spéßi%l": "e%c0d@d", "spa ce": ""}|url_encode|raw }} +{{ {}|url_encode|default("default") }} +{{ 'spéßi%le%c0d@dspa ce'|url_encode }} +--DATA-- +return array() +--EXPECT-- +foo=bar&number=3&sp%C3%A9%C3%9Fi%25l=e%25c0d%40d&spa%20ce= +foo=bar&number=3&sp%C3%A9%C3%9Fi%25l=e%25c0d%40d&spa%20ce= +default +sp%C3%A9%C3%9Fi%25le%25c0d%40dspa%20ce +--TEST-- +"attribute" function +--TEMPLATE-- +{{ attribute(obj, method) }} +{{ attribute(array, item) }} +{{ attribute(obj, "bar", ["a", "b"]) }} +{{ attribute(obj, "bar", arguments) }} +{{ attribute(obj, method) is defined ? 'ok' : 'ko' }} +{{ attribute(obj, nonmethod) is defined ? 'ok' : 'ko' }} +--DATA-- +return array('obj' => new TwigTestFoo(), 'method' => 'foo', 'array' => array('foo' => 'bar'), 'item' => 'foo', 'nonmethod' => 'xxx', 'arguments' => array('a', 'b')) +--EXPECT-- +foo +bar +bar_a-b +bar_a-b +ok +ko +--TEST-- +"block" function +--TEMPLATE-- +{% extends 'base.twig' %} +{% block bar %}BAR{% endblock %} +--TEMPLATE(base.twig)-- +{% block foo %}{{ block('bar') }}{% endblock %} +{% block bar %}BAR_BASE{% endblock %} +--DATA-- +return array() +--EXPECT-- +BARBAR +--TEST-- +"constant" function +--TEMPLATE-- +{{ constant('DATE_W3C') == expect ? 'true' : 'false' }} +{{ constant('ARRAY_AS_PROPS', object) }} +--DATA-- +return array('expect' => DATE_W3C, 'object' => new ArrayObject(array('hi'))); +--EXPECT-- +true +2 +--TEST-- +"cycle" function +--TEMPLATE-- +{% for i in 0..6 %} +{{ cycle(array1, i) }}-{{ cycle(array2, i) }} +{% endfor %} +--DATA-- +return array('array1' => array('odd', 'even'), 'array2' => array('apple', 'orange', 'citrus')) +--EXPECT-- +odd-apple +even-orange +odd-citrus +even-apple +odd-orange +even-citrus +odd-apple +--TEST-- +"date" function +--TEMPLATE-- +{{ date(date, "America/New_York")|date('d/m/Y H:i:s P', false) }} +{{ date(timezone="America/New_York", date=date)|date('d/m/Y H:i:s P', false) }} +--DATA-- +date_default_timezone_set('UTC'); +return array('date' => mktime(13, 45, 0, 10, 4, 2010)) +--EXPECT-- +04/10/2010 09:45:00 -04:00 +04/10/2010 09:45:00 -04:00 +--TEST-- +"date" function +--TEMPLATE-- +{{ date() == date('now') ? 'OK' : 'KO' }} +{{ date(date1) == date('2010-10-04 13:45') ? 'OK' : 'KO' }} +{{ date(date2) == date('2010-10-04 13:45') ? 'OK' : 'KO' }} +{{ date(date3) == date('2010-10-04 13:45') ? 'OK' : 'KO' }} +{{ date(date4) == date('2010-10-04 13:45') ? 'OK' : 'KO' }} +{{ date(date5) == date('1964-01-02 03:04') ? 'OK' : 'KO' }} +--DATA-- +date_default_timezone_set('UTC'); +return array( + 'date1' => mktime(13, 45, 0, 10, 4, 2010), + 'date2' => new DateTime('2010-10-04 13:45'), + 'date3' => '2010-10-04 13:45', + 'date4' => 1286199900, // DateTime::createFromFormat('Y-m-d H:i', '2010-10-04 13:45', new DateTimeZone('UTC'))->getTimestamp() -- A unixtimestamp is always GMT + 'date5' => -189291360, // DateTime::createFromFormat('Y-m-d H:i', '1964-01-02 03:04', new DateTimeZone('UTC'))->getTimestamp(), +) +--EXPECT-- +OK +OK +OK +OK +OK +OK +--TEST-- +"dump" function, xdebug is not loaded or xdebug <2.2-dev is loaded +--CONDITION-- +!extension_loaded('xdebug') || (($r = new ReflectionExtension('xdebug')) && version_compare($r->getVersion(), '2.2-dev', '<')) +--TEMPLATE-- +{{ dump() }} +--DATA-- +return array('foo' => 'foo', 'bar' => 'bar') +--CONFIG-- +return array('debug' => true, 'autoescape' => false); +--TEST-- +"dump" function +--CONDITION-- +!extension_loaded('xdebug') +--TEMPLATE-- +{{ dump('foo') }} +{{ dump('foo', 'bar') }} +--DATA-- +return array('foo' => 'foo', 'bar' => 'bar') +--CONFIG-- +return array('debug' => true, 'autoescape' => false); +--EXPECT-- +string(3) "foo" + +string(3) "foo" +string(3) "bar" +--TEST-- +dynamic function +--TEMPLATE-- +{{ foo_path('bar') }} +{{ a_foo_b_bar('bar') }} +--DATA-- +return array() +--EXPECT-- +foo/bar +a/b/bar +--TEST-- +"include" function +--TEMPLATE-- +{% set tmp = include("foo.twig") %} + +FOO{{ tmp }}BAR +--TEMPLATE(foo.twig)-- +FOOBAR +--DATA-- +return array() +--EXPECT-- +FOO +FOOBARBAR +--TEST-- +"include" function is safe for auto-escaping +--TEMPLATE-- +{{ include("foo.twig") }} +--TEMPLATE(foo.twig)-- +<p>Test</p> +--DATA-- +return array() +--EXPECT-- +<p>Test</p> +--TEST-- +"include" function +--TEMPLATE-- +FOO +{{ include("foo.twig") }} + +BAR +--TEMPLATE(foo.twig)-- +FOOBAR +--DATA-- +return array() +--EXPECT-- +FOO + +FOOBAR + +BAR +--TEST-- +"include" function allows expressions for the template to include +--TEMPLATE-- +FOO +{{ include(foo) }} + +BAR +--TEMPLATE(foo.twig)-- +FOOBAR +--DATA-- +return array('foo' => 'foo.twig') +--EXPECT-- +FOO + +FOOBAR + +BAR +--TEST-- +"include" function +--TEMPLATE-- +{{ include(["foo.twig", "bar.twig"], ignore_missing = true) }} +{{ include("foo.twig", ignore_missing = true) }} +{{ include("foo.twig", ignore_missing = true, variables = {}) }} +{{ include("foo.twig", ignore_missing = true, variables = {}, with_context = true) }} +--DATA-- +return array() +--EXPECT-- +--TEST-- +"include" function +--TEMPLATE-- +{% extends "base.twig" %} + +{% block content %} + {{ parent() }} +{% endblock %} +--TEMPLATE(base.twig)-- +{% block content %} + {{ include("foo.twig") }} +{% endblock %} +--DATA-- +return array(); +--EXCEPTION-- +Twig_Error_Loader: Template "foo.twig" is not defined in "base.twig" at line 3. +--TEST-- +"include" function +--TEMPLATE-- +{{ include("foo.twig") }} +--DATA-- +return array(); +--EXCEPTION-- +Twig_Error_Loader: Template "foo.twig" is not defined in "index.twig" at line 2. +--TEST-- +"include" tag sandboxed +--TEMPLATE-- +{{ include("foo.twig", sandboxed = true) }} +--TEMPLATE(foo.twig)-- +{{ foo|e }} +--DATA-- +return array() +--EXCEPTION-- +Twig_Sandbox_SecurityError: Filter "e" is not allowed in "index.twig" at line 2. +--TEST-- +"include" function accepts Twig_Template instance +--TEMPLATE-- +{{ include(foo) }} FOO +--TEMPLATE(foo.twig)-- +BAR +--DATA-- +return array('foo' => $twig->loadTemplate('foo.twig')) +--EXPECT-- +BAR FOO +--TEST-- +"include" function +--TEMPLATE-- +{{ include(["foo.twig", "bar.twig"]) }} +{{- include(["bar.twig", "foo.twig"]) }} +--TEMPLATE(foo.twig)-- +foo +--DATA-- +return array() +--EXPECT-- +foo +foo +--TEST-- +"include" function accept variables and with_context +--TEMPLATE-- +{{ include("foo.twig") }} +{{- include("foo.twig", with_context = false) }} +{{- include("foo.twig", {'foo1': 'bar'}) }} +{{- include("foo.twig", {'foo1': 'bar'}, with_context = false) }} +--TEMPLATE(foo.twig)-- +{% for k, v in _context %}{{ k }},{% endfor %} +--DATA-- +return array('foo' => 'bar') +--EXPECT-- +foo,global,_parent, +global,_parent, +foo,global,foo1,_parent, +foo1,global,_parent, +--TEST-- +"include" function accept variables +--TEMPLATE-- +{{ include("foo.twig", {'foo': 'bar'}) }} +{{- include("foo.twig", vars) }} +--TEMPLATE(foo.twig)-- +{{ foo }} +--DATA-- +return array('vars' => array('foo' => 'bar')) +--EXPECT-- +bar +bar +--TEST-- +"max" function +--TEMPLATE-- +{{ max([2, 1, 3, 5, 4]) }} +{{ max(2, 1, 3, 5, 4) }} +{{ max({2:"two", 1:"one", 3:"three", 5:"five", 4:"for"}) }} +--DATA-- +return array() +--EXPECT-- +5 +5 +two +--TEST-- +"min" function +--TEMPLATE-- +{{ min(2, 1, 3, 5, 4) }} +{{ min([2, 1, 3, 5, 4]) }} +{{ min({2:"two", 1:"one", 3:"three", 5:"five", 4:"for"}) }} +--DATA-- +return array() +--EXPECT-- +1 +1 +five +--TEST-- +"range" function +--TEMPLATE-- +{{ range(low=0+1, high=10+0, step=2)|join(',') }} +--DATA-- +return array() +--EXPECT-- +1,3,5,7,9 +--TEST-- +"block" function recursively called in a parent template +--TEMPLATE-- +{% extends "ordered_menu.twig" %} +{% block label %}"{{ parent() }}"{% endblock %} +{% block list %}{% set class = 'b' %}{{ parent() }}{% endblock %} +--TEMPLATE(ordered_menu.twig)-- +{% extends "menu.twig" %} +{% block list %}{% set class = class|default('a') %}<ol class="{{ class }}">{{ block('children') }}</ol>{% endblock %} +--TEMPLATE(menu.twig)-- +{% extends "base.twig" %} +{% block list %}<ul>{{ block('children') }}</ul>{% endblock %} +{% block children %}{% set currentItem = item %}{% for item in currentItem %}{{ block('item') }}{% endfor %}{% set item = currentItem %}{% endblock %} +{% block item %}<li>{% if item is not iterable %}{{ block('label') }}{% else %}{{ block('list') }}{% endif %}</li>{% endblock %} +{% block label %}{{ item }}{{ block('unknown') }}{% endblock %} +--TEMPLATE(base.twig)-- +{{ block('list') }} +--DATA-- +return array('item' => array('1', '2', array('3.1', array('3.2.1', '3.2.2'), '3.4'))) +--EXPECT-- +<ol class="b"><li>"1"</li><li>"2"</li><li><ol class="b"><li>"3.1"</li><li><ol class="b"><li>"3.2.1"</li><li>"3.2.2"</li></ol></li><li>"3.4"</li></ol></li></ol> +--TEST-- +"source" function +--TEMPLATE-- +FOO +{{ source("foo.twig") }} + +BAR +--TEMPLATE(foo.twig)-- +{{ foo }}<br /> +--DATA-- +return array() +--EXPECT-- +FOO + +{{ foo }}<br /> + +BAR +--TEST-- +"template_from_string" function +--TEMPLATE-- +{% include template_from_string(template) %} + +{% include template_from_string("Hello {{ name }}") %} +{% include template_from_string('{% extends "parent.twig" %}{% block content %}Hello {{ name }}{% endblock %}') %} +--TEMPLATE(parent.twig)-- +{% block content %}{% endblock %} +--DATA-- +return array('name' => 'Fabien', 'template' => "Hello {{ name }}") +--EXPECT-- +Hello Fabien +Hello Fabien +Hello Fabien +--TEST-- +macro +--TEMPLATE-- +{% from _self import test %} + +{% macro test(a, b = 'bar') -%} +{{ a }}{{ b }} +{%- endmacro %} + +{{ test('foo') }} +{{ test('bar', 'foo') }} +--DATA-- +return array(); +--EXPECT-- +foobar +barfoo +--TEST-- +macro +--TEMPLATE-- +{% import _self as macros %} + +{% macro foo(data) %} + {{ data }} +{% endmacro %} + +{% macro bar() %} + <br /> +{% endmacro %} + +{{ macros.foo(macros.bar()) }} +--DATA-- +return array(); +--EXPECT-- +<br /> +--TEST-- +macro +--TEMPLATE-- +{% from _self import test %} + +{% macro test(this) -%} + {{ this }} +{%- endmacro %} + +{{ test(this) }} +--DATA-- +return array('this' => 'foo'); +--EXPECT-- +foo +--TEST-- +macro +--TEMPLATE-- +{% import _self as test %} +{% from _self import test %} + +{% macro test(a, b) -%} + {{ a|default('a') }}<br /> + {{- b|default('b') }}<br /> +{%- endmacro %} + +{{ test.test() }} +{{ test() }} +{{ test.test(1, "c") }} +{{ test(1, "c") }} +--DATA-- +return array(); +--EXPECT-- +a<br />b<br /> +a<br />b<br /> +1<br />c<br /> +1<br />c<br /> +--TEST-- +macro with a filter +--TEMPLATE-- +{% import _self as test %} + +{% macro test() %} + {% filter escape %}foo<br />{% endfilter %} +{% endmacro %} + +{{ test.test() }} +--DATA-- +return array(); +--EXPECT-- +foo<br /> +--TEST-- +Twig outputs 0 nodes correctly +--TEMPLATE-- +{{ foo }}0{{ foo }} +--DATA-- +return array('foo' => 'foo') +--EXPECT-- +foo0foo +--TEST-- +error in twig extension +--TEMPLATE-- +{{ object.region is not null ? object.regionChoices[object.region] }} +--EXPECT-- +house.region.s +--TEST-- +Twig is able to deal with SimpleXMLElement instances as variables +--CONDITION-- +version_compare(phpversion(), '5.3.0', '>=') +--TEMPLATE-- +Hello '{{ images.image.0.group }}'! +{{ images.image.0.group.attributes.myattr }} +{{ images.children().image.count() }} +{% for image in images %} + - {{ image.group }} +{% endfor %} +--DATA-- +return array('images' => new SimpleXMLElement('<images><image><group myattr="example">foo</group></image><image><group>bar</group></image></images>')) +--EXPECT-- +Hello 'foo'! +example +2 + - foo + - bar +--TEST-- +Twig does not confuse strings with integers in getAttribute() +--TEMPLATE-- +{{ hash['2e2'] }} +--DATA-- +return array('hash' => array('2e2' => 'works')) +--EXPECT-- +works +--TEST-- +"autoescape" tag applies escaping on its children +--TEMPLATE-- +{% autoescape %} +{{ var }}<br /> +{% endautoescape %} +{% autoescape 'html' %} +{{ var }}<br /> +{% endautoescape %} +{% autoescape false %} +{{ var }}<br /> +{% endautoescape %} +{% autoescape true %} +{{ var }}<br /> +{% endautoescape %} +{% autoescape false %} +{{ var }}<br /> +{% endautoescape %} +--DATA-- +return array('var' => '<br />') +--EXPECT-- +<br /><br /> +<br /><br /> +<br /><br /> +<br /><br /> +<br /><br /> +--TEST-- +"autoescape" tag applies escaping on embedded blocks +--TEMPLATE-- +{% autoescape 'html' %} + {% block foo %} + {{ var }} + {% endblock %} +{% endautoescape %} +--DATA-- +return array('var' => '<br />') +--EXPECT-- +<br /> +--TEST-- +"autoescape" tag does not double-escape +--TEMPLATE-- +{% autoescape 'html' %} +{{ var|escape }} +{% endautoescape %} +--DATA-- +return array('var' => '<br />') +--EXPECT-- +<br /> +--TEST-- +"autoescape" tag applies escaping after calling functions +--TEMPLATE-- + +autoescape false +{% autoescape false %} + +safe_br +{{ safe_br() }} + +unsafe_br +{{ unsafe_br() }} + +{% endautoescape %} + +autoescape 'html' +{% autoescape 'html' %} + +safe_br +{{ safe_br() }} + +unsafe_br +{{ unsafe_br() }} + +unsafe_br()|raw +{{ (unsafe_br())|raw }} + +safe_br()|escape +{{ (safe_br())|escape }} + +safe_br()|raw +{{ (safe_br())|raw }} + +unsafe_br()|escape +{{ (unsafe_br())|escape }} + +{% endautoescape %} + +autoescape js +{% autoescape 'js' %} + +safe_br +{{ safe_br() }} + +{% endautoescape %} +--DATA-- +return array() +--EXPECT-- + +autoescape false + +safe_br +<br /> + +unsafe_br +<br /> + + +autoescape 'html' + +safe_br +<br /> + +unsafe_br +<br /> + +unsafe_br()|raw +<br /> + +safe_br()|escape +<br /> + +safe_br()|raw +<br /> + +unsafe_br()|escape +<br /> + + +autoescape js + +safe_br +\x3Cbr\x20\x2F\x3E +--TEST-- +"autoescape" tag does not apply escaping on literals +--TEMPLATE-- +{% autoescape 'html' %} + +1. Simple literal +{{ "<br />" }} + +2. Conditional expression with only literals +{{ true ? "<br />" : "<br>" }} + +3. Conditional expression with a variable +{{ true ? "<br />" : someVar }} + +4. Nested conditionals with only literals +{{ true ? (true ? "<br />" : "<br>") : "\n" }} + +5. Nested conditionals with a variable +{{ true ? (true ? "<br />" : someVar) : "\n" }} + +6. Nested conditionals with a variable marked safe +{{ true ? (true ? "<br />" : someVar|raw) : "\n" }} + +{% endautoescape %} +--DATA-- +return array() +--EXPECT-- + +1. Simple literal +<br /> + +2. Conditional expression with only literals +<br /> + +3. Conditional expression with a variable +<br /> + +4. Nested conditionals with only literals +<br /> + +5. Nested conditionals with a variable +<br /> + +6. Nested conditionals with a variable marked safe +<br /> +--TEST-- +"autoescape" tags can be nested at will +--TEMPLATE-- +{{ var }} +{% autoescape 'html' %} + {{ var }} + {% autoescape false %} + {{ var }} + {% autoescape 'html' %} + {{ var }} + {% endautoescape %} + {{ var }} + {% endautoescape %} + {{ var }} +{% endautoescape %} +{{ var }} +--DATA-- +return array('var' => '<br />') +--EXPECT-- +<br /> + <br /> + <br /> + <br /> + <br /> + <br /> +<br /> +--TEST-- +"autoescape" tag applies escaping to object method calls +--TEMPLATE-- +{% autoescape 'html' %} +{{ user.name }} +{{ user.name|lower }} +{{ user }} +{% endautoescape %} +--EXPECT-- +Fabien<br /> +fabien<br /> +Fabien<br /> +--TEST-- +"autoescape" tag does not escape when raw is used as a filter +--TEMPLATE-- +{% autoescape 'html' %} +{{ var|raw }} +{% endautoescape %} +--DATA-- +return array('var' => '<br />') +--EXPECT-- +<br /> +--TEST-- +"autoescape" tag accepts an escaping strategy +--TEMPLATE-- +{% autoescape true js %}{{ var }}{% endautoescape %} + +{% autoescape true html %}{{ var }}{% endautoescape %} + +{% autoescape 'js' %}{{ var }}{% endautoescape %} + +{% autoescape 'html' %}{{ var }}{% endautoescape %} +--DATA-- +return array('var' => '<br />"') +--EXPECT-- +\x3Cbr\x20\x2F\x3E\x22 +<br />" +\x3Cbr\x20\x2F\x3E\x22 +<br />" +--TEST-- +escape types +--TEMPLATE-- + +1. autoescape 'html' |escape('js') + +{% autoescape 'html' %} +<a onclick="alert("{{ msg|escape('js') }}")"></a> +{% endautoescape %} + +2. autoescape 'html' |escape('js') + +{% autoescape 'html' %} +<a onclick="alert("{{ msg|escape('js') }}")"></a> +{% endautoescape %} + +3. autoescape 'js' |escape('js') + +{% autoescape 'js' %} +<a onclick="alert("{{ msg|escape('js') }}")"></a> +{% endautoescape %} + +4. no escape + +{% autoescape false %} +<a onclick="alert("{{ msg }}")"></a> +{% endautoescape %} + +5. |escape('js')|escape('html') + +{% autoescape false %} +<a onclick="alert("{{ msg|escape('js')|escape('html') }}")"></a> +{% endautoescape %} + +6. autoescape 'html' |escape('js')|escape('html') + +{% autoescape 'html' %} +<a onclick="alert("{{ msg|escape('js')|escape('html') }}")"></a> +{% endautoescape %} + +--DATA-- +return array('msg' => "<>\n'\"") +--EXPECT-- + +1. autoescape 'html' |escape('js') + +<a onclick="alert("\x3C\x3E\x0A\x27\x22")"></a> + +2. autoescape 'html' |escape('js') + +<a onclick="alert("\x3C\x3E\x0A\x27\x22")"></a> + +3. autoescape 'js' |escape('js') + +<a onclick="alert("\x3C\x3E\x0A\x27\x22")"></a> + +4. no escape + +<a onclick="alert("<> +'"")"></a> + +5. |escape('js')|escape('html') + +<a onclick="alert("\x3C\x3E\x0A\x27\x22")"></a> + +6. autoescape 'html' |escape('js')|escape('html') + +<a onclick="alert("\x3C\x3E\x0A\x27\x22")"></a> + +--TEST-- +"autoescape" tag do not applies escaping on filter arguments +--TEMPLATE-- +{% autoescape 'html' %} +{{ var|nl2br("<br />") }} +{{ var|nl2br("<br />"|escape) }} +{{ var|nl2br(sep) }} +{{ var|nl2br(sep|raw) }} +{{ var|nl2br(sep|escape) }} +{% endautoescape %} +--DATA-- +return array('var' => "<Fabien>\nTwig", 'sep' => '<br />') +--EXPECT-- +<Fabien><br /> +Twig +<Fabien><br /> +Twig +<Fabien><br /> +Twig +<Fabien><br /> +Twig +<Fabien><br /> +Twig +--TEST-- +"autoescape" tag applies escaping after calling filters +--TEMPLATE-- +{% autoescape 'html' %} + +(escape_and_nl2br is an escaper filter) + +1. Don't escape escaper filter output +( var is escaped by |escape_and_nl2br, line-breaks are added, + the output is not escaped ) +{{ var|escape_and_nl2br }} + +2. Don't escape escaper filter output +( var is escaped by |escape_and_nl2br, line-breaks are added, + the output is not escaped, |raw is redundant ) +{{ var|escape_and_nl2br|raw }} + +3. Explicit escape +( var is escaped by |escape_and_nl2br, line-breaks are added, + the output is explicitly escaped by |escape ) +{{ var|escape_and_nl2br|escape }} + +4. Escape non-escaper filter output +( var is upper-cased by |upper, + the output is auto-escaped ) +{{ var|upper }} + +5. Escape if last filter is not an escaper +( var is escaped by |escape_and_nl2br, line-breaks are added, + the output is upper-cased by |upper, + the output is auto-escaped as |upper is not an escaper ) +{{ var|escape_and_nl2br|upper }} + +6. Don't escape escaper filter output +( var is upper cased by upper, + the output is escaped by |escape_and_nl2br, line-breaks are added, + the output is not escaped as |escape_and_nl2br is an escaper ) +{{ var|upper|escape_and_nl2br }} + +7. Escape if last filter is not an escaper +( the output of |format is "<b>" ~ var ~ "</b>", + the output is auto-escaped ) +{{ "<b>%s</b>"|format(var) }} + +8. Escape if last filter is not an escaper +( the output of |format is "<b>" ~ var ~ "</b>", + |raw is redundant, + the output is auto-escaped ) +{{ "<b>%s</b>"|raw|format(var) }} + +9. Don't escape escaper filter output +( the output of |format is "<b>" ~ var ~ "</b>", + the output is not escaped due to |raw filter at the end ) +{{ "<b>%s</b>"|format(var)|raw }} + +10. Don't escape escaper filter output +( the output of |format is "<b>" ~ var ~ "</b>", + the output is not escaped due to |raw filter at the end, + the |raw filter on var is redundant ) +{{ "<b>%s</b>"|format(var|raw)|raw }} + +{% endautoescape %} +--DATA-- +return array('var' => "<Fabien>\nTwig") +--EXPECT-- + +(escape_and_nl2br is an escaper filter) + +1. Don't escape escaper filter output +( var is escaped by |escape_and_nl2br, line-breaks are added, + the output is not escaped ) +<Fabien><br /> +Twig + +2. Don't escape escaper filter output +( var is escaped by |escape_and_nl2br, line-breaks are added, + the output is not escaped, |raw is redundant ) +<Fabien><br /> +Twig + +3. Explicit escape +( var is escaped by |escape_and_nl2br, line-breaks are added, + the output is explicitly escaped by |escape ) +&lt;Fabien&gt;<br /> +Twig + +4. Escape non-escaper filter output +( var is upper-cased by |upper, + the output is auto-escaped ) +<FABIEN> +TWIG + +5. Escape if last filter is not an escaper +( var is escaped by |escape_and_nl2br, line-breaks are added, + the output is upper-cased by |upper, + the output is auto-escaped as |upper is not an escaper ) +&LT;FABIEN&GT;<BR /> +TWIG + +6. Don't escape escaper filter output +( var is upper cased by upper, + the output is escaped by |escape_and_nl2br, line-breaks are added, + the output is not escaped as |escape_and_nl2br is an escaper ) +<FABIEN><br /> +TWIG + +7. Escape if last filter is not an escaper +( the output of |format is "<b>" ~ var ~ "</b>", + the output is auto-escaped ) +<b><Fabien> +Twig</b> + +8. Escape if last filter is not an escaper +( the output of |format is "<b>" ~ var ~ "</b>", + |raw is redundant, + the output is auto-escaped ) +<b><Fabien> +Twig</b> + +9. Don't escape escaper filter output +( the output of |format is "<b>" ~ var ~ "</b>", + the output is not escaped due to |raw filter at the end ) +<b><Fabien> +Twig</b> + +10. Don't escape escaper filter output +( the output of |format is "<b>" ~ var ~ "</b>", + the output is not escaped due to |raw filter at the end, + the |raw filter on var is redundant ) +<b><Fabien> +Twig</b> +--TEST-- +"autoescape" tag applies escaping after calling filters, and before calling pre_escape filters +--TEMPLATE-- +{% autoescape 'html' %} + +(nl2br is pre_escaped for "html" and declared safe for "html") + +1. Pre-escape and don't post-escape +( var|escape|nl2br ) +{{ var|nl2br }} + +2. Don't double-pre-escape +( var|escape|nl2br ) +{{ var|escape|nl2br }} + +3. Don't escape safe values +( var|raw|nl2br ) +{{ var|raw|nl2br }} + +4. Don't escape safe values +( var|escape|nl2br|nl2br ) +{{ var|nl2br|nl2br }} + +5. Re-escape values that are escaped for an other contexts +( var|escape_something|escape|nl2br ) +{{ var|escape_something|nl2br }} + +6. Still escape when using filters not declared safe +( var|escape|nl2br|upper|escape ) +{{ var|nl2br|upper }} + +{% endautoescape %} +--DATA-- +return array('var' => "<Fabien>\nTwig") +--EXPECT-- + +(nl2br is pre_escaped for "html" and declared safe for "html") + +1. Pre-escape and don't post-escape +( var|escape|nl2br ) +<Fabien><br /> +Twig + +2. Don't double-pre-escape +( var|escape|nl2br ) +<Fabien><br /> +Twig + +3. Don't escape safe values +( var|raw|nl2br ) +<Fabien><br /> +Twig + +4. Don't escape safe values +( var|escape|nl2br|nl2br ) +<Fabien><br /><br /> +Twig + +5. Re-escape values that are escaped for an other contexts +( var|escape_something|escape|nl2br ) +<FABIEN><br /> +TWIG + +6. Still escape when using filters not declared safe +( var|escape|nl2br|upper|escape ) +&LT;FABIEN&GT;<BR /> +TWIG + +--TEST-- +"autoescape" tag handles filters preserving the safety +--TEMPLATE-- +{% autoescape 'html' %} + +(preserves_safety is preserving safety for "html") + +1. Unsafe values are still unsafe +( var|preserves_safety|escape ) +{{ var|preserves_safety }} + +2. Safe values are still safe +( var|escape|preserves_safety ) +{{ var|escape|preserves_safety }} + +3. Re-escape values that are escaped for an other contexts +( var|escape_something|preserves_safety|escape ) +{{ var|escape_something|preserves_safety }} + +4. Still escape when using filters not declared safe +( var|escape|preserves_safety|replace({'FABIEN': 'FABPOT'})|escape ) +{{ var|escape|preserves_safety|replace({'FABIEN': 'FABPOT'}) }} + +{% endautoescape %} +--DATA-- +return array('var' => "<Fabien>\nTwig") +--EXPECT-- + +(preserves_safety is preserving safety for "html") + +1. Unsafe values are still unsafe +( var|preserves_safety|escape ) +<FABIEN> +TWIG + +2. Safe values are still safe +( var|escape|preserves_safety ) +<FABIEN> +TWIG + +3. Re-escape values that are escaped for an other contexts +( var|escape_something|preserves_safety|escape ) +<FABIEN> +TWIG + +4. Still escape when using filters not declared safe +( var|escape|preserves_safety|replace({'FABIEN': 'FABPOT'})|escape ) +&LT;FABPOT&GT; +TWIG + +--TEST-- +"block" tag +--TEMPLATE-- +{% block title1 %}FOO{% endblock %} +{% block title2 foo|lower %} +--TEMPLATE(foo.twig)-- +{% block content %}{% endblock %} +--DATA-- +return array('foo' => 'bar') +--EXPECT-- +FOObar +--TEST-- +"block" tag +--TEMPLATE-- +{% block content %} + {% block content %} + {% endblock %} +{% endblock %} +--DATA-- +return array() +--EXCEPTION-- +Twig_Error_Syntax: The block 'content' has already been defined line 2 in "index.twig" at line 3 +--TEST-- +"§" special chars in a block name +--TEMPLATE-- +{% block § %} +§ +{% endblock § %} +--DATA-- +return array() +--EXPECT-- +§ +--TEST-- +"embed" tag +--TEMPLATE-- +FOO +{% embed "foo.twig" %} + {% block c1 %} + {{ parent() }} + block1extended + {% endblock %} +{% endembed %} + +BAR +--TEMPLATE(foo.twig)-- +A +{% block c1 %} + block1 +{% endblock %} +B +{% block c2 %} + block2 +{% endblock %} +C +--DATA-- +return array() +--EXPECT-- +FOO + +A + block1 + + block1extended + B + block2 +C +BAR +--TEST-- +"embed" tag +--TEMPLATE(index.twig)-- +FOO +{% embed "foo.twig" %} + {% block c1 %} + {{ nothing }} + {% endblock %} +{% endembed %} +BAR +--TEMPLATE(foo.twig)-- +{% block c1 %}{% endblock %} +--DATA-- +return array() +--EXCEPTION-- +Twig_Error_Runtime: Variable "nothing" does not exist in "index.twig" at line 5 +--TEST-- +"embed" tag +--TEMPLATE-- +FOO +{% embed "foo.twig" %} + {% block c1 %} + {{ parent() }} + block1extended + {% endblock %} +{% endembed %} + +{% embed "foo.twig" %} + {% block c1 %} + {{ parent() }} + block1extended + {% endblock %} +{% endembed %} + +BAR +--TEMPLATE(foo.twig)-- +A +{% block c1 %} + block1 +{% endblock %} +B +{% block c2 %} + block2 +{% endblock %} +C +--DATA-- +return array() +--EXPECT-- +FOO + +A + block1 + + block1extended + B + block2 +C + +A + block1 + + block1extended + B + block2 +C +BAR +--TEST-- +"embed" tag +--TEMPLATE-- +{% embed "foo.twig" %} + {% block c1 %} + {{ parent() }} + {% embed "foo.twig" %} + {% block c1 %} + {{ parent() }} + block1extended + {% endblock %} + {% endembed %} + + {% endblock %} +{% endembed %} +--TEMPLATE(foo.twig)-- +A +{% block c1 %} + block1 +{% endblock %} +B +{% block c2 %} + block2 +{% endblock %} +C +--DATA-- +return array() +--EXPECT-- +A + block1 + + +A + block1 + + block1extended + B + block2 +C + B + block2 +C +--TEST-- +"embed" tag +--TEMPLATE-- +{% extends "base.twig" %} + +{% block c1 %} + {{ parent() }} + blockc1baseextended +{% endblock %} + +{% block c2 %} + {{ parent() }} + + {% embed "foo.twig" %} + {% block c1 %} + {{ parent() }} + block1extended + {% endblock %} + {% endembed %} +{% endblock %} +--TEMPLATE(base.twig)-- +A +{% block c1 %} + blockc1base +{% endblock %} +{% block c2 %} + blockc2base +{% endblock %} +B +--TEMPLATE(foo.twig)-- +A +{% block c1 %} + block1 +{% endblock %} +B +{% block c2 %} + block2 +{% endblock %} +C +--DATA-- +return array() +--EXPECT-- +A + blockc1base + + blockc1baseextended + blockc2base + + + +A + block1 + + block1extended + B + block2 +CB--TEST-- +"filter" tag applies a filter on its children +--TEMPLATE-- +{% filter upper %} +Some text with a {{ var }} +{% endfilter %} +--DATA-- +return array('var' => 'var') +--EXPECT-- +SOME TEXT WITH A VAR +--TEST-- +"filter" tag applies a filter on its children +--TEMPLATE-- +{% filter json_encode|raw %}test{% endfilter %} +--DATA-- +return array() +--EXPECT-- +"test" +--TEST-- +"filter" tags accept multiple chained filters +--TEMPLATE-- +{% filter lower|title %} + {{ var }} +{% endfilter %} +--DATA-- +return array('var' => 'VAR') +--EXPECT-- + Var +--TEST-- +"filter" tags can be nested at will +--TEMPLATE-- +{% filter lower|title %} + {{ var }} + {% filter upper %} + {{ var }} + {% endfilter %} + {{ var }} +{% endfilter %} +--DATA-- +return array('var' => 'var') +--EXPECT-- + Var + Var + Var +--TEST-- +"filter" tag applies the filter on "for" tags +--TEMPLATE-- +{% filter upper %} +{% for item in items %} +{{ item }} +{% endfor %} +{% endfilter %} +--DATA-- +return array('items' => array('a', 'b')) +--EXPECT-- +A +B +--TEST-- +"filter" tag applies the filter on "if" tags +--TEMPLATE-- +{% filter upper %} +{% if items %} +{{ items|join(', ') }} +{% endif %} + +{% if items.3 is defined %} +FOO +{% else %} +{{ items.1 }} +{% endif %} + +{% if items.3 is defined %} +FOO +{% elseif items.1 %} +{{ items.0 }} +{% endif %} + +{% endfilter %} +--DATA-- +return array('items' => array('a', 'b')) +--EXPECT-- +A, B + +B + +A +--TEST-- +"for" tag takes a condition +--TEMPLATE-- +{% for i in 1..5 if i is odd -%} + {{ loop.index }}.{{ i }}{{ foo.bar }} +{% endfor %} +--DATA-- +return array('foo' => array('bar' => 'X')) +--CONFIG-- +return array('strict_variables' => false) +--EXPECT-- +1.1X +2.3X +3.5X +--TEST-- +"for" tag keeps the context safe +--TEMPLATE-- +{% for item in items %} + {% for item in items %} + * {{ item }} + {% endfor %} + * {{ item }} +{% endfor %} +--DATA-- +return array('items' => array('a', 'b')) +--EXPECT-- + * a + * b + * a + * a + * b + * b +--TEST-- +"for" tag can use an "else" clause +--TEMPLATE-- +{% for item in items %} + * {{ item }} +{% else %} + no item +{% endfor %} +--DATA-- +return array('items' => array('a', 'b')) +--EXPECT-- + * a + * b +--DATA-- +return array('items' => array()) +--EXPECT-- + no item +--DATA-- +return array() +--CONFIG-- +return array('strict_variables' => false) +--EXPECT-- + no item +--TEST-- +"for" tag does not reset inner variables +--TEMPLATE-- +{% for i in 1..2 %} + {% for j in 0..2 %} + {{k}}{% set k = k+1 %} {{ loop.parent.loop.index }} + {% endfor %} +{% endfor %} +--DATA-- +return array('k' => 0) +--EXPECT-- + 0 1 + 1 1 + 2 1 + 3 2 + 4 2 + 5 2 +--TEST-- +"for" tag can iterate over keys and values +--TEMPLATE-- +{% for key, item in items %} + * {{ key }}/{{ item }} +{% endfor %} +--DATA-- +return array('items' => array('a', 'b')) +--EXPECT-- + * 0/a + * 1/b +--TEST-- +"for" tag can iterate over keys +--TEMPLATE-- +{% for key in items|keys %} + * {{ key }} +{% endfor %} +--DATA-- +return array('items' => array('a', 'b')) +--EXPECT-- + * 0 + * 1 +--TEST-- +"for" tag adds a loop variable to the context locally +--TEMPLATE-- +{% for item in items %} +{% endfor %} +{% if loop is not defined %}WORKS{% endif %} +--DATA-- +return array('items' => array()) +--EXPECT-- +WORKS +--TEST-- +"for" tag adds a loop variable to the context +--TEMPLATE-- +{% for item in items %} + * {{ loop.index }}/{{ loop.index0 }} + * {{ loop.revindex }}/{{ loop.revindex0 }} + * {{ loop.first }}/{{ loop.last }}/{{ loop.length }} + +{% endfor %} +--DATA-- +return array('items' => array('a', 'b')) +--EXPECT-- + * 1/0 + * 2/1 + * 1//2 + + * 2/1 + * 1/0 + * /1/2 +--TEST-- +"for" tag +--TEMPLATE-- +{% for i, item in items if loop.last > 0 %} +{% endfor %} +--DATA-- +return array('items' => array('a', 'b')) +--EXCEPTION-- +Twig_Error_Syntax: The "loop" variable cannot be used in a looping condition in "index.twig" at line 2 +--TEST-- +"for" tag +--TEMPLATE-- +{% for i, item in items if i > 0 %} + {{ loop.last }} +{% endfor %} +--DATA-- +return array('items' => array('a', 'b')) +--EXCEPTION-- +Twig_Error_Syntax: The "loop.last" variable is not defined when looping with a condition in "index.twig" at line 3 +--TEST-- +"for" tag can use an "else" clause +--TEMPLATE-- +{% for item in items %} + {% for item in items1 %} + * {{ item }} + {% else %} + no {{ item }} + {% endfor %} +{% else %} + no item1 +{% endfor %} +--DATA-- +return array('items' => array('a', 'b'), 'items1' => array()) +--EXPECT-- +no a + no b +--TEST-- +"for" tag iterates over iterable and countable objects +--TEMPLATE-- +{% for item in items %} + * {{ item }} + * {{ loop.index }}/{{ loop.index0 }} + * {{ loop.revindex }}/{{ loop.revindex0 }} + * {{ loop.first }}/{{ loop.last }}/{{ loop.length }} + +{% endfor %} + +{% for key, value in items %} + * {{ key }}/{{ value }} +{% endfor %} + +{% for key in items|keys %} + * {{ key }} +{% endfor %} +--DATA-- +class ItemsIteratorCountable implements Iterator, Countable +{ + protected $values = array('foo' => 'bar', 'bar' => 'foo'); + public function current() { return current($this->values); } + public function key() { return key($this->values); } + public function next() { return next($this->values); } + public function rewind() { return reset($this->values); } + public function valid() { return false !== current($this->values); } + public function count() { return count($this->values); } +} +return array('items' => new ItemsIteratorCountable()) +--EXPECT-- + * bar + * 1/0 + * 2/1 + * 1//2 + + * foo + * 2/1 + * 1/0 + * /1/2 + + + * foo/bar + * bar/foo + + * foo + * bar +--TEST-- +"for" tag iterates over iterable objects +--TEMPLATE-- +{% for item in items %} + * {{ item }} + * {{ loop.index }}/{{ loop.index0 }} + * {{ loop.first }} + +{% endfor %} + +{% for key, value in items %} + * {{ key }}/{{ value }} +{% endfor %} + +{% for key in items|keys %} + * {{ key }} +{% endfor %} +--DATA-- +class ItemsIterator implements Iterator +{ + protected $values = array('foo' => 'bar', 'bar' => 'foo'); + public function current() { return current($this->values); } + public function key() { return key($this->values); } + public function next() { return next($this->values); } + public function rewind() { return reset($this->values); } + public function valid() { return false !== current($this->values); } +} +return array('items' => new ItemsIterator()) +--EXPECT-- + * bar + * 1/0 + * 1 + + * foo + * 2/1 + * + + + * foo/bar + * bar/foo + + * foo + * bar +--TEST-- +"for" tags can be nested +--TEMPLATE-- +{% for key, item in items %} +* {{ key }} ({{ loop.length }}): +{% for value in item %} + * {{ value }} ({{ loop.length }}) +{% endfor %} +{% endfor %} +--DATA-- +return array('items' => array('a' => array('a1', 'a2', 'a3'), 'b' => array('b1'))) +--EXPECT-- +* a (2): + * a1 (3) + * a2 (3) + * a3 (3) +* b (2): + * b1 (1) +--TEST-- +"for" tag iterates over item values +--TEMPLATE-- +{% for item in items %} + * {{ item }} +{% endfor %} +--DATA-- +return array('items' => array('a', 'b')) +--EXPECT-- + * a + * b +--TEST-- +global variables +--TEMPLATE-- +{% include "included.twig" %} +{% from "included.twig" import foobar %} +{{ foobar() }} +--TEMPLATE(included.twig)-- +{% macro foobar() %} +called foobar +{% endmacro %} +--DATA-- +return array(); +--EXPECT-- +called foobar +--TEST-- +"if" creates a condition +--TEMPLATE-- +{% if a is defined %} + {{ a }} +{% elseif b is defined %} + {{ b }} +{% else %} + NOTHING +{% endif %} +--DATA-- +return array('a' => 'a') +--EXPECT-- + a +--DATA-- +return array('b' => 'b') +--EXPECT-- + b +--DATA-- +return array() +--EXPECT-- + NOTHING +--TEST-- +"if" takes an expression as a test +--TEMPLATE-- +{% if a < 2 %} + A1 +{% elseif a > 10 %} + A2 +{% else %} + A3 +{% endif %} +--DATA-- +return array('a' => 1) +--EXPECT-- + A1 +--DATA-- +return array('a' => 12) +--EXPECT-- + A2 +--DATA-- +return array('a' => 7) +--EXPECT-- + A3 +--TEST-- +"include" tag +--TEMPLATE-- +FOO +{% include "foo.twig" %} + +BAR +--TEMPLATE(foo.twig)-- +FOOBAR +--DATA-- +return array() +--EXPECT-- +FOO + +FOOBAR +BAR +--TEST-- +"include" tag allows expressions for the template to include +--TEMPLATE-- +FOO +{% include foo %} + +BAR +--TEMPLATE(foo.twig)-- +FOOBAR +--DATA-- +return array('foo' => 'foo.twig') +--EXPECT-- +FOO + +FOOBAR +BAR +--TEST-- +"include" tag +--TEMPLATE-- +{% include ["foo.twig", "bar.twig"] ignore missing %} +{% include "foo.twig" ignore missing %} +{% include "foo.twig" ignore missing with {} %} +{% include "foo.twig" ignore missing with {} only %} +--DATA-- +return array() +--EXPECT-- +--TEST-- +"include" tag +--TEMPLATE-- +{% extends "base.twig" %} + +{% block content %} + {{ parent() }} +{% endblock %} +--TEMPLATE(base.twig)-- +{% block content %} + {% include "foo.twig" %} +{% endblock %} +--DATA-- +return array(); +--EXCEPTION-- +Twig_Error_Loader: Template "foo.twig" is not defined in "base.twig" at line 3. +--TEST-- +"include" tag +--TEMPLATE-- +{% include "foo.twig" %} +--DATA-- +return array(); +--EXCEPTION-- +Twig_Error_Loader: Template "foo.twig" is not defined in "index.twig" at line 2. +--TEST-- +"include" tag accept variables and only +--TEMPLATE-- +{% include "foo.twig" %} +{% include "foo.twig" only %} +{% include "foo.twig" with {'foo1': 'bar'} %} +{% include "foo.twig" with {'foo1': 'bar'} only %} +--TEMPLATE(foo.twig)-- +{% for k, v in _context %}{{ k }},{% endfor %} +--DATA-- +return array('foo' => 'bar') +--EXPECT-- +foo,global,_parent, +global,_parent, +foo,global,foo1,_parent, +foo1,global,_parent, +--TEST-- +"include" tag accepts Twig_Template instance +--TEMPLATE-- +{% include foo %} FOO +--TEMPLATE(foo.twig)-- +BAR +--DATA-- +return array('foo' => $twig->loadTemplate('foo.twig')) +--EXPECT-- +BAR FOO +--TEST-- +"include" tag +--TEMPLATE-- +{% include ["foo.twig", "bar.twig"] %} +{% include ["bar.twig", "foo.twig"] %} +--TEMPLATE(foo.twig)-- +foo +--DATA-- +return array() +--EXPECT-- +foo +foo +--TEST-- +"include" tag accept variables +--TEMPLATE-- +{% include "foo.twig" with {'foo': 'bar'} %} +{% include "foo.twig" with vars %} +--TEMPLATE(foo.twig)-- +{{ foo }} +--DATA-- +return array('vars' => array('foo' => 'bar')) +--EXPECT-- +bar +bar +--TEST-- +"extends" tag +--TEMPLATE-- +{% extends "foo.twig" %} + +{% block content %} +FOO +{% endblock %} +--TEMPLATE(foo.twig)-- +{% block content %}{% endblock %} +--DATA-- +return array() +--EXPECT-- +FOO +--TEST-- +block_expr2 +--TEMPLATE-- +{% extends "base2.twig" %} + +{% block element -%} + Element: + {{- parent() -}} +{% endblock %} +--TEMPLATE(base2.twig)-- +{% extends "base.twig" %} +--TEMPLATE(base.twig)-- +{% spaceless %} +{% block element -%} + <div> + {%- if item.children is defined %} + {%- for item in item.children %} + {{- block('element') -}} + {% endfor %} + {%- endif -%} + </div> +{%- endblock %} +{% endspaceless %} +--DATA-- +return array( + 'item' => array( + 'children' => array( + null, + null, + ) + ) +) +--EXPECT-- +Element:<div>Element:<div></div>Element:<div></div></div> +--TEST-- +block_expr +--TEMPLATE-- +{% extends "base.twig" %} + +{% block element -%} + Element: + {{- parent() -}} +{% endblock %} +--TEMPLATE(base.twig)-- +{% spaceless %} +{% block element -%} + <div> + {%- if item.children is defined %} + {%- for item in item.children %} + {{- block('element') -}} + {% endfor %} + {%- endif -%} + </div> +{%- endblock %} +{% endspaceless %} +--DATA-- +return array( + 'item' => array( + 'children' => array( + null, + null, + ) + ) +) +--EXPECT-- +Element:<div>Element:<div></div>Element:<div></div></div> +--TEST-- +"extends" tag +--TEMPLATE-- +{% extends standalone ? foo : 'bar.twig' %} + +{% block content %}{{ parent() }}FOO{% endblock %} +--TEMPLATE(foo.twig)-- +{% block content %}FOO{% endblock %} +--TEMPLATE(bar.twig)-- +{% block content %}BAR{% endblock %} +--DATA-- +return array('foo' => 'foo.twig', 'standalone' => true) +--EXPECT-- +FOOFOO +--TEST-- +"extends" tag +--TEMPLATE-- +{% extends foo %} + +{% block content %} +FOO +{% endblock %} +--TEMPLATE(foo.twig)-- +{% block content %}{% endblock %} +--DATA-- +return array('foo' => 'foo.twig') +--EXPECT-- +FOO +--TEST-- +"extends" tag +--TEMPLATE-- +{% extends "foo.twig" %} +--TEMPLATE(foo.twig)-- +{% block content %}FOO{% endblock %} +--DATA-- +return array() +--EXPECT-- +FOO +--TEST-- +"extends" tag +--TEMPLATE-- +{% extends ["foo.twig", "bar.twig"] %} +--TEMPLATE(bar.twig)-- +{% block content %} +foo +{% endblock %} +--DATA-- +return array() +--EXPECT-- +foo +--TEST-- +"extends" tag +--TEMPLATE-- +{% extends "layout.twig" %}{% block content %}{{ parent() }}index {% endblock %} +--TEMPLATE(layout.twig)-- +{% extends "base.twig" %}{% block content %}{{ parent() }}layout {% endblock %} +--TEMPLATE(base.twig)-- +{% block content %}base {% endblock %} +--DATA-- +return array() +--EXPECT-- +base layout index +--TEST-- +"block" tag +--TEMPLATE-- +{% block content %} + CONTENT + {%- block subcontent -%} + SUBCONTENT + {%- endblock -%} + ENDCONTENT +{% endblock %} +--TEMPLATE(foo.twig)-- +--DATA-- +return array() +--EXPECT-- +CONTENTSUBCONTENTENDCONTENT +--TEST-- +"block" tag +--TEMPLATE-- +{% extends "foo.twig" %} + +{% block content %} + {% block subcontent %} + {% block subsubcontent %} + SUBSUBCONTENT + {% endblock %} + {% endblock %} +{% endblock %} +--TEMPLATE(foo.twig)-- +{% block content %} + {% block subcontent %} + SUBCONTENT + {% endblock %} +{% endblock %} +--DATA-- +return array() +--EXPECT-- +SUBSUBCONTENT +--TEST-- +"extends" tag +--TEMPLATE-- +{% extends "layout.twig" %} +{% block inside %}INSIDE{% endblock inside %} +--TEMPLATE(layout.twig)-- +{% extends "base.twig" %} +{% block body %} + {% block inside '' %} +{% endblock body %} +--TEMPLATE(base.twig)-- +{% block body '' %} +--DATA-- +return array() +--EXPECT-- +INSIDE +--TEST-- +"extends" tag +--TEMPLATE-- +{% extends foo ? 'foo.twig' : 'bar.twig' %} +--TEMPLATE(foo.twig)-- +FOO +--TEMPLATE(bar.twig)-- +BAR +--DATA-- +return array('foo' => true) +--EXPECT-- +FOO +--DATA-- +return array('foo' => false) +--EXPECT-- +BAR +--TEST-- +"extends" tag +--TEMPLATE-- +{% block content %} + {% extends "foo.twig" %} +{% endblock %} +--EXCEPTION-- +Twig_Error_Syntax: Cannot extend from a block in "index.twig" at line 3 +--TEST-- +"extends" tag +--TEMPLATE-- +{% extends "base.twig" %} +{% block content %}{% include "included.twig" %}{% endblock %} + +{% block footer %}Footer{% endblock %} +--TEMPLATE(included.twig)-- +{% extends "base.twig" %} +{% block content %}Included Content{% endblock %} +--TEMPLATE(base.twig)-- +{% block content %}Default Content{% endblock %} + +{% block footer %}Default Footer{% endblock %} +--DATA-- +return array() +--EXPECT-- +Included Content +Default Footer +Footer +--TEST-- +"extends" tag +--TEMPLATE-- +{% extends "foo.twig" %} + +{% block content %} + {% block inside %} + INSIDE OVERRIDDEN + {% endblock %} + + BEFORE + {{ parent() }} + AFTER +{% endblock %} +--TEMPLATE(foo.twig)-- +{% block content %} + BAR +{% endblock %} +--DATA-- +return array() +--EXPECT-- + +INSIDE OVERRIDDEN + + BEFORE + BAR + + AFTER +--TEST-- +"extends" tag +--TEMPLATE-- +{% extends "foo.twig" %} + +{% block content %}{{ parent() }}FOO{{ parent() }}{% endblock %} +--TEMPLATE(foo.twig)-- +{% block content %}BAR{% endblock %} +--DATA-- +return array() +--EXPECT-- +BARFOOBAR +--TEST-- +"parent" tag +--TEMPLATE-- +{% use 'foo.twig' %} + +{% block content %} + {{ parent() }} +{% endblock %} +--TEMPLATE(foo.twig)-- +{% block content %}BAR{% endblock %} +--DATA-- +return array() +--EXPECT-- +BAR +--TEST-- +"parent" tag +--TEMPLATE-- +{% block content %} + {{ parent() }} +{% endblock %} +--EXCEPTION-- +Twig_Error_Syntax: Calling "parent" on a template that does not extend nor "use" another template is forbidden in "index.twig" at line 3 +--TEST-- +"extends" tag accepts Twig_Template instance +--TEMPLATE-- +{% extends foo %} + +{% block content %} +{{ parent() }}FOO +{% endblock %} +--TEMPLATE(foo.twig)-- +{% block content %}BAR{% endblock %} +--DATA-- +return array('foo' => $twig->loadTemplate('foo.twig')) +--EXPECT-- +BARFOO +--TEST-- +"parent" function +--TEMPLATE-- +{% extends "parent.twig" %} + +{% use "use1.twig" %} +{% use "use2.twig" %} + +{% block content_parent %} + {{ parent() }} +{% endblock %} + +{% block content_use1 %} + {{ parent() }} +{% endblock %} + +{% block content_use2 %} + {{ parent() }} +{% endblock %} + +{% block content %} + {{ block('content_use1_only') }} + {{ block('content_use2_only') }} +{% endblock %} +--TEMPLATE(parent.twig)-- +{% block content_parent 'content_parent' %} +{% block content_use1 'content_parent' %} +{% block content_use2 'content_parent' %} +{% block content '' %} +--TEMPLATE(use1.twig)-- +{% block content_use1 'content_use1' %} +{% block content_use2 'content_use1' %} +{% block content_use1_only 'content_use1_only' %} +--TEMPLATE(use2.twig)-- +{% block content_use2 'content_use2' %} +{% block content_use2_only 'content_use2_only' %} +--DATA-- +return array() +--EXPECT-- + content_parent + content_use1 + content_use2 + content_use1_only + content_use2_only +--TEST-- +"macro" tag +--TEMPLATE-- +{% import _self as macros %} + +{{ macros.input('username') }} +{{ macros.input('password', null, 'password', 1) }} + +{% macro input(name, value, type, size) %} + <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}"> +{% endmacro %} +--DATA-- +return array() +--EXPECT-- + <input type="text" name="username" value="" size="20"> + + <input type="password" name="password" value="" size="1"> +--TEST-- +"macro" tag supports name for endmacro +--TEMPLATE-- +{% import _self as macros %} + +{{ macros.foo() }} +{{ macros.bar() }} + +{% macro foo() %}foo{% endmacro %} +{% macro bar() %}bar{% endmacro bar %} +--DATA-- +return array() +--EXPECT-- +foo +bar + +--TEST-- +"macro" tag +--TEMPLATE-- +{% import 'forms.twig' as forms %} + +{{ forms.input('username') }} +{{ forms.input('password', null, 'password', 1) }} +--TEMPLATE(forms.twig)-- +{% macro input(name, value, type, size) %} + <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}"> +{% endmacro %} +--DATA-- +return array() +--EXPECT-- + <input type="text" name="username" value="" size="20"> + + <input type="password" name="password" value="" size="1"> +--TEST-- +"macro" tag +--TEMPLATE-- +{% from 'forms.twig' import foo %} +{% from 'forms.twig' import foo as foobar, bar %} + +{{ foo('foo') }} +{{ foobar('foo') }} +{{ bar('foo') }} +--TEMPLATE(forms.twig)-- +{% macro foo(name) %}foo{{ name }}{% endmacro %} +{% macro bar(name) %}bar{{ name }}{% endmacro %} +--DATA-- +return array() +--EXPECT-- +foofoo +foofoo +barfoo +--TEST-- +"macro" tag +--TEMPLATE-- +{% from 'forms.twig' import foo %} + +{{ foo('foo') }} +{{ foo() }} +--TEMPLATE(forms.twig)-- +{% macro foo(name) %}{{ name|default('foo') }}{{ global }}{% endmacro %} +--DATA-- +return array() +--EXPECT-- +fooglobal +fooglobal +--TEST-- +"macro" tag +--TEMPLATE-- +{% import _self as forms %} + +{{ forms.input('username') }} +{{ forms.input('password', null, 'password', 1) }} + +{% macro input(name, value, type, size) %} + <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}"> +{% endmacro %} +--DATA-- +return array() +--EXPECT-- + <input type="text" name="username" value="" size="20"> + + <input type="password" name="password" value="" size="1"> +--TEST-- +"raw" tag +--TEMPLATE-- +{% raw %} +{{ foo }} +{% endraw %} +--DATA-- +return array() +--EXPECT-- +{{ foo }} +--TEST-- +"raw" tag +--TEMPLATE-- +{% raw %} +{{ foo }} +{% endverbatim %} +--DATA-- +return array() +--EXCEPTION-- +Twig_Error_Syntax: Unexpected end of file: Unclosed "raw" block in "index.twig" at line 2 +--TEST-- +"raw" tag +--TEMPLATE-- +1*** + +{%- raw %} + {{ 'bla' }} +{% endraw %} + +1*** +2*** + +{%- raw -%} + {{ 'bla' }} +{% endraw %} + +2*** +3*** + +{%- raw -%} + {{ 'bla' }} +{% endraw -%} + +3*** +4*** + +{%- raw -%} + {{ 'bla' }} +{%- endraw %} + +4*** +5*** + +{%- raw -%} + {{ 'bla' }} +{%- endraw -%} + +5*** +--DATA-- +return array() +--EXPECT-- +1*** + {{ 'bla' }} + + +1*** +2***{{ 'bla' }} + + +2*** +3***{{ 'bla' }} +3*** +4***{{ 'bla' }} + +4*** +5***{{ 'bla' }}5*** +--TEST-- +sandbox tag +--TEMPLATE-- +{%- sandbox %} + {%- include "foo.twig" %} + a +{%- endsandbox %} +--TEMPLATE(foo.twig)-- +foo +--EXCEPTION-- +Twig_Error_Syntax: Only "include" tags are allowed within a "sandbox" section in "index.twig" at line 4 +--TEST-- +sandbox tag +--TEMPLATE-- +{%- sandbox %} + {%- include "foo.twig" %} + + {% if 1 %} + {%- include "foo.twig" %} + {% endif %} +{%- endsandbox %} +--TEMPLATE(foo.twig)-- +foo +--EXCEPTION-- +Twig_Error_Syntax: Only "include" tags are allowed within a "sandbox" section in "index.twig" at line 5 +--TEST-- +sandbox tag +--TEMPLATE-- +{%- sandbox %} + {%- include "foo.twig" %} +{%- endsandbox %} + +{%- sandbox %} + {%- include "foo.twig" %} + {%- include "foo.twig" %} +{%- endsandbox %} + +{%- sandbox %}{% include "foo.twig" %}{% endsandbox %} +--TEMPLATE(foo.twig)-- +foo +--DATA-- +return array() +--EXPECT-- +foo +foo +foo +foo +--TEST-- +"set" tag +--TEMPLATE-- +{% set foo = 'foo' %} +{% set bar = 'foo<br />' %} + +{{ foo }} +{{ bar }} + +{% set foo, bar = 'foo', 'bar' %} + +{{ foo }}{{ bar }} +--DATA-- +return array() +--EXPECT-- +foo +foo<br /> + + +foobar +--TEST-- +"set" tag block empty capture +--TEMPLATE-- +{% set foo %}{% endset %} + +{% if foo %}FAIL{% endif %} +--DATA-- +return array() +--EXPECT-- +--TEST-- +"set" tag block capture +--TEMPLATE-- +{% set foo %}f<br />o<br />o{% endset %} + +{{ foo }} +--DATA-- +return array() +--EXPECT-- +f<br />o<br />o +--TEST-- +"set" tag +--TEMPLATE-- +{% set foo, bar = 'foo' ~ 'bar', 'bar' ~ 'foo' %} + +{{ foo }} +{{ bar }} +--DATA-- +return array() +--EXPECT-- +foobar +barfoo +--TEST-- +"spaceless" tag removes whites between HTML tags +--TEMPLATE-- +{% spaceless %} + + <div> <div> foo </div> </div> + +{% endspaceless %} +--DATA-- +return array() +--EXPECT-- +<div><div> foo </div></div> +--TEST-- +"§" custom tag +--TEMPLATE-- +{% § %} +--DATA-- +return array() +--EXPECT-- +§ +--TEST-- +Whitespace trimming on tags. +--TEMPLATE-- +{{ 5 * '{#-'|length }} +{{ '{{-'|length * 5 + '{%-'|length }} + +Trim on control tag: +{% for i in range(1, 9) -%} + {{ i }} +{%- endfor %} + + +Trim on output tag: +{% for i in range(1, 9) %} + {{- i -}} +{% endfor %} + + +Trim comments: + +{#- Invisible -#} + +After the comment. + +Trim leading space: +{% if leading %} + + {{- leading }} +{% endif %} + +{%- if leading %} + {{- leading }} + +{%- endif %} + + +Trim trailing space: +{% if trailing -%} + {{ trailing -}} + +{% endif -%} + +Combined: + +{%- if both -%} +<ul> + <li> {{- both -}} </li> +</ul> + +{%- endif -%} + +end +--DATA-- +return array('leading' => 'leading space', 'trailing' => 'trailing space', 'both' => 'both') +--EXPECT-- +15 +18 + +Trim on control tag: +123456789 + +Trim on output tag: +123456789 + +Trim comments:After the comment. + +Trim leading space: +leading space +leading space + +Trim trailing space: +trailing spaceCombined:<ul> + <li>both</li> +</ul>end +--TEST-- +"use" tag +--TEMPLATE-- +{% use "blocks.twig" with content as foo %} + +{{ block('foo') }} +--TEMPLATE(blocks.twig)-- +{% block content 'foo' %} +--DATA-- +return array() +--EXPECT-- +foo +--TEST-- +"use" tag +--TEMPLATE-- +{% use "blocks.twig" %} + +{{ block('content') }} +--TEMPLATE(blocks.twig)-- +{% block content 'foo' %} +--DATA-- +return array() +--EXPECT-- +foo +--TEST-- +"use" tag +--TEMPLATE-- +{% use "foo.twig" %} +--TEMPLATE(foo.twig)-- +{% use "bar.twig" %} +--TEMPLATE(bar.twig)-- +--DATA-- +return array() +--EXPECT-- +--TEST-- +"use" tag +--TEMPLATE-- +{% use "foo.twig" %} + +{{ block('content') }} +{{ block('foo') }} +{{ block('bar') }} +--TEMPLATE(foo.twig)-- +{% use "bar.twig" %} + +{% block content 'foo' %} +{% block foo 'foo' %} +--TEMPLATE(bar.twig)-- +{% block content 'bar' %} +{% block bar 'bar' %} +--DATA-- +return array() +--EXPECT-- +foo +foo +bar +--TEST-- +"use" tag +--TEMPLATE-- +{% use "ancestor.twig" %} +{% use "parent.twig" %} + +{{ block('container') }} +--TEMPLATE(parent.twig)-- +{% block sub_container %} + <div class="overriden_sub_container">overriden sub_container</div> +{% endblock %} +--TEMPLATE(ancestor.twig)-- +{% block container %} + <div class="container">{{ block('sub_container') }}</div> +{% endblock %} + +{% block sub_container %} + <div class="sub_container">sub_container</div> +{% endblock %} +--DATA-- +return array() +--EXPECT-- +<div class="container"> <div class="overriden_sub_container">overriden sub_container</div> +</div> +--TEST-- +"use" tag +--TEMPLATE-- +{% use "parent.twig" %} + +{{ block('container') }} +--TEMPLATE(parent.twig)-- +{% use "ancestor.twig" %} + +{% block sub_container %} + <div class="overriden_sub_container">overriden sub_container</div> +{% endblock %} +--TEMPLATE(ancestor.twig)-- +{% block container %} + <div class="container">{{ block('sub_container') }}</div> +{% endblock %} + +{% block sub_container %} + <div class="sub_container">sub_container</div> +{% endblock %} +--DATA-- +return array() +--EXPECT-- +<div class="container"> <div class="overriden_sub_container">overriden sub_container</div> +</div> +--TEST-- +"use" tag +--TEMPLATE-- +{% use "foo.twig" with content as foo_content %} +{% use "bar.twig" %} + +{{ block('content') }} +{{ block('foo') }} +{{ block('bar') }} +{{ block('foo_content') }} +--TEMPLATE(foo.twig)-- +{% block content 'foo' %} +{% block foo 'foo' %} +--TEMPLATE(bar.twig)-- +{% block content 'bar' %} +{% block bar 'bar' %} +--DATA-- +return array() +--EXPECT-- +bar +foo +bar +foo +--TEST-- +"use" tag +--TEMPLATE-- +{% use "foo.twig" %} +{% use "bar.twig" %} + +{{ block('content') }} +{{ block('foo') }} +{{ block('bar') }} +--TEMPLATE(foo.twig)-- +{% block content 'foo' %} +{% block foo 'foo' %} +--TEMPLATE(bar.twig)-- +{% block content 'bar' %} +{% block bar 'bar' %} +--DATA-- +return array() +--EXPECT-- +bar +foo +bar +--TEST-- +"use" tag +--TEMPLATE-- +{% use 'file2.html.twig'%} +{% block foobar %} + {{- parent() -}} + Content of block (second override) +{% endblock foobar %} +--TEMPLATE(file2.html.twig)-- +{% use 'file1.html.twig' %} +{% block foobar %} + {{- parent() -}} + Content of block (first override) +{% endblock foobar %} +--TEMPLATE(file1.html.twig)-- +{% block foobar -%} + Content of block +{% endblock foobar %} +--DATA-- +return array() +--EXPECT-- +Content of block +Content of block (first override) +Content of block (second override) +--TEST-- +"use" tag +--TEMPLATE-- +{% use 'file2.html.twig' %} +{% use 'file1.html.twig' with foo %} +{% block foo %} + {{- parent() -}} + Content of foo (second override) +{% endblock foo %} +{% block bar %} + {{- parent() -}} + Content of bar (second override) +{% endblock bar %} +--TEMPLATE(file2.html.twig)-- +{% use 'file1.html.twig' %} +{% block foo %} + {{- parent() -}} + Content of foo (first override) +{% endblock foo %} +{% block bar %} + {{- parent() -}} + Content of bar (first override) +{% endblock bar %} +--TEMPLATE(file1.html.twig)-- +{% block foo -%} + Content of foo +{% endblock foo %} +{% block bar -%} + Content of bar +{% endblock bar %} +--DATA-- +return array() +--EXPECT-- +Content of foo +Content of foo (first override) +Content of foo (second override) +Content of bar +Content of bar (second override) +--TEST-- +"use" tag +--TEMPLATE-- +{% use 'file2.html.twig' with foobar as base_base_foobar %} +{% block foobar %} + {{- block('base_base_foobar') -}} + Content of block (second override) +{% endblock foobar %} +--TEMPLATE(file2.html.twig)-- +{% use 'file1.html.twig' with foobar as base_foobar %} +{% block foobar %} + {{- block('base_foobar') -}} + Content of block (first override) +{% endblock foobar %} +--TEMPLATE(file1.html.twig)-- +{% block foobar -%} + Content of block +{% endblock foobar %} +--DATA-- +return array() +--EXPECT-- +Content of block +Content of block (first override) +Content of block (second override) +--TEST-- +"verbatim" tag +--TEMPLATE-- +{% verbatim %} +{{ foo }} +{% endverbatim %} +--DATA-- +return array() +--EXPECT-- +{{ foo }} +--TEST-- +"verbatim" tag +--TEMPLATE-- +{% verbatim %} +{{ foo }} +{% endraw %} +--DATA-- +return array() +--EXCEPTION-- +Twig_Error_Syntax: Unexpected end of file: Unclosed "verbatim" block in "index.twig" at line 2 +--TEST-- +"verbatim" tag +--TEMPLATE-- +1*** + +{%- verbatim %} + {{ 'bla' }} +{% endverbatim %} + +1*** +2*** + +{%- verbatim -%} + {{ 'bla' }} +{% endverbatim %} + +2*** +3*** + +{%- verbatim -%} + {{ 'bla' }} +{% endverbatim -%} + +3*** +4*** + +{%- verbatim -%} + {{ 'bla' }} +{%- endverbatim %} + +4*** +5*** + +{%- verbatim -%} + {{ 'bla' }} +{%- endverbatim -%} + +5*** +--DATA-- +return array() +--EXPECT-- +1*** + {{ 'bla' }} + + +1*** +2***{{ 'bla' }} + + +2*** +3***{{ 'bla' }} +3*** +4***{{ 'bla' }} + +4*** +5***{{ 'bla' }}5*** +--TEST-- +array index test +--TEMPLATE-- +{% for key, value in days %} +{{ key }} +{% endfor %} +--DATA-- +return array('days' => array( + 1 => array('money' => 9), + 2 => array('money' => 21), + 3 => array('money' => 38), + 4 => array('money' => 6), + 18 => array('money' => 6), + 19 => array('money' => 3), + 31 => array('money' => 11), +)); +--EXPECT-- +1 +2 +3 +4 +18 +19 +31 +--TEST-- +"const" test +--TEMPLATE-- +{{ 8 is constant('E_NOTICE') ? 'ok' : 'no' }} +{{ 'bar' is constant('TwigTestFoo::BAR_NAME') ? 'ok' : 'no' }} +{{ value is constant('TwigTestFoo::BAR_NAME') ? 'ok' : 'no' }} +{{ 2 is constant('ARRAY_AS_PROPS', object) ? 'ok' : 'no' }} +--DATA-- +return array('value' => 'bar', 'object' => new ArrayObject(array('hi'))); +--EXPECT-- +ok +ok +ok +ok--TEST-- +"defined" test +--TEMPLATE-- +{{ definedVar is defined ? 'ok' : 'ko' }} +{{ definedVar is not defined ? 'ko' : 'ok' }} +{{ undefinedVar is defined ? 'ko' : 'ok' }} +{{ undefinedVar is not defined ? 'ok' : 'ko' }} +{{ zeroVar is defined ? 'ok' : 'ko' }} +{{ nullVar is defined ? 'ok' : 'ko' }} +{{ nested.definedVar is defined ? 'ok' : 'ko' }} +{{ nested['definedVar'] is defined ? 'ok' : 'ko' }} +{{ nested.definedVar is not defined ? 'ko' : 'ok' }} +{{ nested.undefinedVar is defined ? 'ko' : 'ok' }} +{{ nested['undefinedVar'] is defined ? 'ko' : 'ok' }} +{{ nested.undefinedVar is not defined ? 'ok' : 'ko' }} +{{ nested.zeroVar is defined ? 'ok' : 'ko' }} +{{ nested.nullVar is defined ? 'ok' : 'ko' }} +{{ nested.definedArray.0 is defined ? 'ok' : 'ko' }} +{{ nested['definedArray'][0] is defined ? 'ok' : 'ko' }} +{{ object.foo is defined ? 'ok' : 'ko' }} +{{ object.undefinedMethod is defined ? 'ko' : 'ok' }} +{{ object.getFoo() is defined ? 'ok' : 'ko' }} +{{ object.getFoo('a') is defined ? 'ok' : 'ko' }} +{{ object.undefinedMethod() is defined ? 'ko' : 'ok' }} +{{ object.undefinedMethod('a') is defined ? 'ko' : 'ok' }} +{{ object.self.foo is defined ? 'ok' : 'ko' }} +{{ object.self.undefinedMethod is defined ? 'ko' : 'ok' }} +{{ object.undefinedMethod.self is defined ? 'ko' : 'ok' }} +--DATA-- +return array( + 'definedVar' => 'defined', + 'zeroVar' => 0, + 'nullVar' => null, + 'nested' => array( + 'definedVar' => 'defined', + 'zeroVar' => 0, + 'nullVar' => null, + 'definedArray' => array(0), + ), + 'object' => new TwigTestFoo(), +); +--EXPECT-- +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +--DATA-- +return array( + 'definedVar' => 'defined', + 'zeroVar' => 0, + 'nullVar' => null, + 'nested' => array( + 'definedVar' => 'defined', + 'zeroVar' => 0, + 'nullVar' => null, + 'definedArray' => array(0), + ), + 'object' => new TwigTestFoo(), +); +--CONFIG-- +return array('strict_variables' => false) +--EXPECT-- +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +ok +--TEST-- +"empty" test +--TEMPLATE-- +{{ foo is empty ? 'ok' : 'ko' }} +{{ bar is empty ? 'ok' : 'ko' }} +{{ foobar is empty ? 'ok' : 'ko' }} +{{ array is empty ? 'ok' : 'ko' }} +{{ zero is empty ? 'ok' : 'ko' }} +{{ string is empty ? 'ok' : 'ko' }} +{{ countable_empty is empty ? 'ok' : 'ko' }} +{{ countable_not_empty is empty ? 'ok' : 'ko' }} +{{ markup_empty is empty ? 'ok' : 'ko' }} +{{ markup_not_empty is empty ? 'ok' : 'ko' }} +--DATA-- + +class CountableStub implements Countable +{ + private $items; + + public function __construct(array $items) + { + $this->items = $items; + } + + public function count() + { + return count($this->items); + } +} +return array( + 'foo' => '', 'bar' => null, 'foobar' => false, 'array' => array(), 'zero' => 0, 'string' => '0', + 'countable_empty' => new CountableStub(array()), 'countable_not_empty' => new CountableStub(array(1, 2)), + 'markup_empty' => new Twig_Markup('', 'UTF-8'), 'markup_not_empty' => new Twig_Markup('test', 'UTF-8'), +); +--EXPECT-- +ok +ok +ok +ok +ko +ko +ok +ko +ok +ko +--TEST-- +"even" test +--TEMPLATE-- +{{ 1 is even ? 'ko' : 'ok' }} +{{ 2 is even ? 'ok' : 'ko' }} +{{ 1 is not even ? 'ok' : 'ko' }} +{{ 2 is not even ? 'ko' : 'ok' }} +--DATA-- +return array() +--EXPECT-- +ok +ok +ok +ok +--TEST-- +Twig supports the in operator +--TEMPLATE-- +{% if bar in foo %} +TRUE +{% endif %} +{% if not (bar in foo) %} +{% else %} +TRUE +{% endif %} +{% if bar not in foo %} +{% else %} +TRUE +{% endif %} +{% if 'a' in bar %} +TRUE +{% endif %} +{% if 'c' not in bar %} +TRUE +{% endif %} +{% if '' not in bar %} +TRUE +{% endif %} +{% if '' in '' %} +TRUE +{% endif %} +{% if '0' not in '' %} +TRUE +{% endif %} +{% if 'a' not in '0' %} +TRUE +{% endif %} +{% if '0' in '0' %} +TRUE +{% endif %} +{{ false in [0, 1] ? 'TRUE' : 'FALSE' }} +{{ true in [0, 1] ? 'TRUE' : 'FALSE' }} +{{ '0' in [0, 1] ? 'TRUE' : 'FALSE' }} +{{ '' in [0, 1] ? 'TRUE' : 'FALSE' }} +{{ 0 in ['', 1] ? 'TRUE' : 'FALSE' }} +{{ '' in 'foo' ? 'TRUE' : 'FALSE' }} +{{ 0 in 'foo' ? 'TRUE' : 'FALSE' }} +{{ false in 'foo' ? 'TRUE' : 'FALSE' }} +{{ true in '100' ? 'TRUE' : 'FALSE' }} +{{ [] in 'Array' ? 'TRUE' : 'FALSE' }} +{{ [] in [true, false] ? 'TRUE' : 'FALSE' }} +{{ [] in [true, ''] ? 'TRUE' : 'FALSE' }} +{{ [] in [true, []] ? 'TRUE' : 'FALSE' }} +{{ dir_object in 'foo'~dir_name ? 'TRUE' : 'FALSE' }} +{{ 5 in 125 ? 'TRUE' : 'FALSE' }} +--DATA-- +return array('bar' => 'bar', 'foo' => array('bar' => 'bar'), 'dir_name' => dirname(__FILE__), 'dir_object' => new SplFileInfo(dirname(__FILE__))) +--EXPECT-- +TRUE +TRUE +TRUE +TRUE +TRUE +TRUE +TRUE +TRUE +TRUE +FALSE +FALSE +FALSE +FALSE +FALSE +TRUE +FALSE +FALSE +FALSE +FALSE +FALSE +FALSE +TRUE +FALSE +FALSE +--TEST-- +Twig supports the in operator when using objects +--TEMPLATE-- +{% if object in object_list %} +TRUE +{% endif %} +--DATA-- +$foo = new TwigTestFoo(); +$foo1 = new TwigTestFoo(); + +$foo->position = $foo1; +$foo1->position = $foo; + +return array( + 'object' => $foo, + 'object_list' => array($foo1, $foo), +); +--EXPECT-- +TRUE +--TEST-- +"iterable" test +--TEMPLATE-- +{{ foo is iterable ? 'ok' : 'ko' }} +{{ traversable is iterable ? 'ok' : 'ko' }} +{{ obj is iterable ? 'ok' : 'ko' }} +{{ val is iterable ? 'ok' : 'ko' }} +--DATA-- +return array( + 'foo' => array(), + 'traversable' => new ArrayIterator(array()), + 'obj' => new stdClass(), + 'val' => 'test', +); +--EXPECT-- +ok +ok +ko +ko--TEST-- +"odd" test +--TEMPLATE-- +{{ 1 is odd ? 'ok' : 'ko' }} +{{ 2 is odd ? 'ko' : 'ok' }} +--DATA-- +return array() +--EXPECT-- +ok +ok diff --git a/tests/examplefiles/unicode.go b/tests/examplefiles/unicode.go new file mode 100644 index 00000000..d4bef4d1 --- /dev/null +++ b/tests/examplefiles/unicode.go @@ -0,0 +1,10 @@ +package main + +import "fmt" + +func main() { + 世界 := "Hello, world!" + さようなら := "Goodbye, world!" + fmt.Println(世界) + fmt.Println(さようなら) +} diff --git a/tests/examplefiles/unicode.js b/tests/examplefiles/unicode.js new file mode 100644 index 00000000..8f553f6f --- /dev/null +++ b/tests/examplefiles/unicode.js @@ -0,0 +1,6 @@ +var école; +var sinθ; +var เมือง; +var a\u1234b; + +var nbsp; diff --git a/tests/examplefiles/test.bas b/tests/examplefiles/vbnet_test.bas index af5f2574..af5f2574 100644 --- a/tests/examplefiles/test.bas +++ b/tests/examplefiles/vbnet_test.bas diff --git a/tests/examplefiles/vctreestatus_hg b/tests/examplefiles/vctreestatus_hg new file mode 100644 index 00000000..193ed803 --- /dev/null +++ b/tests/examplefiles/vctreestatus_hg @@ -0,0 +1,4 @@ +M LICENSE +M setup.py +! setup.cfg +? vctreestatus_hg diff --git a/tests/examplefiles/vimrc b/tests/examplefiles/vimrc new file mode 100644 index 00000000..d2f9cd1b --- /dev/null +++ b/tests/examplefiles/vimrc @@ -0,0 +1,21 @@ +" A comment + +:py print "py" +::pyt print 'pyt' + pyth print '''pyth''' + : pytho print "pytho" +python print """python""" + + : : python<<E OF +print """my script""" + +def MyFunc(str): + """ My Function """ + print str +E OF + +let py = 42 +echo py + +let foo = 42 +echo foo diff --git a/tests/examplefiles/vpath.mk b/tests/examplefiles/vpath.mk new file mode 100644 index 00000000..a7f18fc3 --- /dev/null +++ b/tests/examplefiles/vpath.mk @@ -0,0 +1,16 @@ +vpath %.c src +vpath %.h header +EXEC=hello +SRC= hello.c main.c +OBJ= $(SRC:.c=.o) + +all: $(EXEC) + +hello: $(OBJ) + $(CC) -o $@ $^ $(LDFLAGS) + +main.o: hello.h + +%.o: %.c + $(CC) -I header -o $@ \ + -c $< $(CFLAGS) |