S-expressions: Difference between revisions

Content added Content deleted
m (→‎{{header|F#}}: Corrected header as suggested on the Count examples/Full list/Tier 4 talk page)
m (syntax highlighting fixup automation)
Line 21: Line 21:


The reader should be able to read the following input
The reader should be able to read the following input
<lang lisp>((data "quoted data" 123 4.5)
<syntaxhighlight lang="lisp">((data "quoted data" 123 4.5)
(data (!@# (4.5) "(more" "data)")))</lang>
(data (!@# (4.5) "(more" "data)")))</syntaxhighlight>
and turn it into a native datastructure. (see the [[#Pike|Pike]], [[#Python|Python]] and [[#Ruby|Ruby]] implementations for examples of native data structures.)
and turn it into a native datastructure. (see the [[#Pike|Pike]], [[#Python|Python]] and [[#Ruby|Ruby]] implementations for examples of native data structures.)


Line 36: Line 36:
{{trans|Nim}}
{{trans|Nim}}


<lang 11l>T Token
<syntaxhighlight lang="11l">T Token
T.enum Kind
T.enum Kind
INT
INT
Line 170: Line 170:
assert(0B)
assert(0B)


print(parse().to_str())</lang>
print(parse().to_str())</syntaxhighlight>


{{out}}
{{out}}
Line 186: Line 186:
Specification of package S_Expr:
Specification of package S_Expr:


<lang Ada>with Ada.Strings.Unbounded;
<syntaxhighlight lang="ada">with Ada.Strings.Unbounded;
private with Ada.Containers.Indefinite_Vectors;
private with Ada.Containers.Indefinite_Vectors;


Line 240: Line 240:
end record;
end record;


end S_Expr;</lang>
end S_Expr;</syntaxhighlight>


The implementation of S_Expr:
The implementation of S_Expr:


<lang Ada>with Ada.Integer_Text_IO, Ada.Float_Text_IO;
<syntaxhighlight lang="ada">with Ada.Integer_Text_IO, Ada.Float_Text_IO;


package body S_Expr is
package body S_Expr is
Line 298: Line 298:
end Print;
end Print;


end S_Expr;</lang>
end S_Expr;</syntaxhighlight>


Specification and Implementation of S_Expr.Parser (a child package of S_Expr):
Specification and Implementation of S_Expr.Parser (a child package of S_Expr):


<lang Ada>generic -- child of a generic package must be a generic unit
<syntaxhighlight lang="ada">generic -- child of a generic package must be a generic unit
package S_Expr.Parser is
package S_Expr.Parser is


Line 308: Line 308:
-- the result of a parse process is always a list of expressions
-- the result of a parse process is always a list of expressions


end S_Expr.Parser;</lang>
end S_Expr.Parser;</syntaxhighlight>


<lang Ada>with Ada.Integer_Text_IO, Ada.Float_Text_IO;
<syntaxhighlight lang="ada">with Ada.Integer_Text_IO, Ada.Float_Text_IO;


package body S_Expr.Parser is
package body S_Expr.Parser is
Line 419: Line 419:
end Parse;
end Parse;


end S_Expr.Parser;</lang>
end S_Expr.Parser;</syntaxhighlight>


The main program Test_S_Expr:
The main program Test_S_Expr:


<lang Ada>with S_Expr.Parser, Ada.Text_IO;
<syntaxhighlight lang="ada">with S_Expr.Parser, Ada.Text_IO;


procedure Test_S_Expr is
procedure Test_S_Expr is
Line 445: Line 445:
Expression_List.First.Print(Indention => 0);
Expression_List.First.Print(Indention => 0);
-- Parse will output a list of S-Expressions. We need the first Expression.
-- Parse will output a list of S-Expressions. We need the first Expression.
end Test_S_Expr;</lang>
end Test_S_Expr;</syntaxhighlight>


{{out}}
{{out}}
Line 473: Line 473:


=={{header|ALGOL 68}}==
=={{header|ALGOL 68}}==
<lang algol68># S-Expressions #
<syntaxhighlight lang="algol68"># S-Expressions #
CHAR nl = REPR 10;
CHAR nl = REPR 10;
# mode representing an S-expression #
# mode representing an S-expression #
Line 599: Line 599:
+ nl
+ nl
)
)
)</lang>
)</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 706: Line 706:




<lang APL>sexp←{
<syntaxhighlight lang="apl">sexp←{
wspace←' ',⎕TC ⍝ whitespace is space, tab, cr, lf
wspace←' ',⎕TC ⍝ whitespace is space, tab, cr, lf


Line 769: Line 769:
}
}


</syntaxhighlight>
</lang>


=={{header|Arturo}}==
=={{header|Arturo}}==
<lang rebol>code: {
<syntaxhighlight lang="rebol">code: {
((data "quoted data" 123 4.5)
((data "quoted data" 123 4.5)
(data (!@# (4.5) "(more" "data)")))
(data (!@# (4.5) "(more" "data)")))
Line 779: Line 779:
s: first to :block code
s: first to :block code
inspect.muted s
inspect.muted s
print as.code s</lang>
print as.code s</syntaxhighlight>


{{out}}
{{out}}
Line 807: Line 807:


=={{header|AutoHotkey}}==
=={{header|AutoHotkey}}==
<lang AutoHotkey>S_Expressions(Str){
<syntaxhighlight lang="autohotkey">S_Expressions(Str){
Str := RegExReplace(Str, "s)(?<![\\])"".*?[^\\]""(*SKIP)(*F)|((?<![\\])[)(]|\s)", "`n$0`n")
Str := RegExReplace(Str, "s)(?<![\\])"".*?[^\\]""(*SKIP)(*F)|((?<![\\])[)(]|\s)", "`n$0`n")
Str := RegExReplace(Str, "`am)^\s*\v+") , Cnt := 0
Str := RegExReplace(Str, "`am)^\s*\v+") , Cnt := 0
Line 822: Line 822:
Res .= "`t"
Res .= "`t"
return Res
return Res
}</lang>
}</syntaxhighlight>
Examples:<lang AutoHotkey>Str =
Examples:<syntaxhighlight lang="autohotkey">Str =
(
(
((data da\(\)ta "quot\\ed data" 123 4.5)
((data da\(\)ta "quot\\ed data" 123 4.5)
("data" (!@# (4.5) "(mo\"re" "data)")))
("data" (!@# (4.5) "(mo\"re" "data)")))
)
)
MsgBox, 262144, , % S_Expressions(Str)</lang>
MsgBox, 262144, , % S_Expressions(Str)</syntaxhighlight>
{{out}}
{{out}}
<pre>(
<pre>(
Line 854: Line 854:


=={{header|C}}==
=={{header|C}}==
<lang c>#include <stdio.h>
<syntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <ctype.h>
#include <ctype.h>
Line 1,079: Line 1,079:
print_expr(x, 0);
print_expr(x, 0);
return 0;
return 0;
}</lang>
}</syntaxhighlight>
{{out}}<lang>input is:
{{out}}<syntaxhighlight lang="text">input is:
((data da\(\)ta "quot\\ed data" 123 4.5)
((data da\(\)ta "quot\\ed data" 123 4.5)
("data" (!@# (4.5) "(mo\"re" "data)")))
("data" (!@# (4.5) "(mo\"re" "data)")))
Line 1,103: Line 1,103:
)
)
)
)
)</lang>
)</syntaxhighlight>


=={{header|C sharp|C#}}==
=={{header|C sharp|C#}}==
Line 1,110: Line 1,110:
Git repository with code and tests can be found here: https://github.com/ichensky/SExpression/tree/rosettacode
Git repository with code and tests can be found here: https://github.com/ichensky/SExpression/tree/rosettacode


<lang csharp>
<syntaxhighlight lang="csharp">
using System;
using System;
using System.Collections.Generic;
using System.Collections.Generic;
Line 1,157: Line 1,157:
}
}


</syntaxhighlight>
</lang>
<lang csharp>
<syntaxhighlight lang="csharp">
using System;
using System;
using System.Collections.Generic;
using System.Collections.Generic;
Line 1,343: Line 1,343:
}
}
}
}
</syntaxhighlight>
</lang>
<lang csharp>
<syntaxhighlight lang="csharp">
using System;
using System;
using System.Collections.Generic;
using System.Collections.Generic;
Line 1,365: Line 1,365:
}
}
}
}
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 1,378: Line 1,378:
apart from writing it out, which fulfils this task's requirements. With some more work
apart from writing it out, which fulfils this task's requirements. With some more work
this code might actually be useful.
this code might actually be useful.
<lang cpp>#include <cctype>
<syntaxhighlight lang="cpp">#include <cctype>
#include <iomanip>
#include <iomanip>
#include <iostream>
#include <iostream>
Line 1,648: Line 1,648:
}
}
return 0;
return 0;
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 1,674: Line 1,674:


=={{header|Ceylon}}==
=={{header|Ceylon}}==
<lang ceylon>class Symbol(symbol) {
<syntaxhighlight lang="ceylon">class Symbol(symbol) {
shared String symbol;
shared String symbol;
string => symbol;
string => symbol;
Line 1,842: Line 1,842:
prettyPrint(tree);
prettyPrint(tree);
}
}
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 1,868: Line 1,868:
=={{header|CoffeeScript}}==
=={{header|CoffeeScript}}==
{{improve|CoffeeScript|This solution does not reproduce unquoted strings as per task description}}
{{improve|CoffeeScript|This solution does not reproduce unquoted strings as per task description}}
<lang coffeescript>
<syntaxhighlight lang="coffeescript">
# This code works with Lisp-like s-expressions.
# This code works with Lisp-like s-expressions.
#
#
Line 1,999: Line 1,999:
console.log "output:\n#{pp output}\n"
console.log "output:\n#{pp output}\n"
console.log "round trip:\n#{sexp output}\n"
console.log "round trip:\n#{sexp output}\n"
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<lang>
<syntaxhighlight lang="text">
> coffee sexp.coffee
> coffee sexp.coffee
input:
input:
Line 2,031: Line 2,031:
round trip:
round trip:
(("data" "quoted data with escaped \"" 123 4.5 "14") ("data" ("!@#" (4.5) "(more" "data)")))
(("data" "quoted data with escaped \"" 123 4.5 "14") ("data" ("!@#" (4.5) "(more" "data)")))
</syntaxhighlight>
</lang>


=={{header|Common Lisp}}==
=={{header|Common Lisp}}==
Line 2,049: Line 2,049:
Unfortunately, our pointy-haired boss has asked you to write a parser for an unusual s-expression syntax that uses square brackets instead of parenthesis. In most programming languages, this would necessitate writing an entire parser. Fortunately, the Common Lisp reader can be modified through the use of macro-characters to accomplish this task. When the reader parses a macro-character token, a function associated with the macro-character is called. As evidenced below, modifying the behavior of the Lisp reader by setting macro-character functions to handle additional sytax requires far less work than writing a complete parser from scratch.
Unfortunately, our pointy-haired boss has asked you to write a parser for an unusual s-expression syntax that uses square brackets instead of parenthesis. In most programming languages, this would necessitate writing an entire parser. Fortunately, the Common Lisp reader can be modified through the use of macro-characters to accomplish this task. When the reader parses a macro-character token, a function associated with the macro-character is called. As evidenced below, modifying the behavior of the Lisp reader by setting macro-character functions to handle additional sytax requires far less work than writing a complete parser from scratch.


<lang lisp>(defun lsquare-reader (stream char)
<syntaxhighlight lang="lisp">(defun lsquare-reader (stream char)
(declare (ignore char))
(declare (ignore char))
(read-delimited-list #\] stream t))
(read-delimited-list #\] stream t))
(set-macro-character #\[ #'lsquare-reader) ;;Call the lsquare-reader function when a '[' token is parsed
(set-macro-character #\[ #'lsquare-reader) ;;Call the lsquare-reader function when a '[' token is parsed
(set-macro-character #\] (get-macro-character #\) nil)) ;;Do the same thing as ')' when a ']' token is parsed</lang>
(set-macro-character #\] (get-macro-character #\) nil)) ;;Do the same thing as ')' when a ']' token is parsed</syntaxhighlight>
Unit test code:
Unit test code:
<lang lisp>;;A list of unit tests. Each test is a cons in which the car (left side) contains the
<syntaxhighlight lang="lisp">;;A list of unit tests. Each test is a cons in which the car (left side) contains the
;;test string and the cdr (right side) the expected result of reading the S-Exp.
;;test string and the cdr (right side) the expected result of reading the S-Exp.
(setf unit-tests
(setf unit-tests
Line 2,070: Line 2,070:
(dolist (test unit-tests)
(dolist (test unit-tests)
(format t "String: ~23s Expected: ~23s Actual: ~s~%"
(format t "String: ~23s Expected: ~23s Actual: ~s~%"
(car test) (cdr test) (read-from-string (car test)))))</lang>
(car test) (cdr test) (read-from-string (car test)))))</syntaxhighlight>
{{out| Unit test output}}
{{out| Unit test output}}
<pre>CL-USER> (run-tests)
<pre>CL-USER> (run-tests)
Line 2,104: Line 2,104:
===Writing S-Expressions===
===Writing S-Expressions===
The next step in this task is to write a standard Lisp s-expression in the square bracket notation.
The next step in this task is to write a standard Lisp s-expression in the square bracket notation.
<lang lisp>(defun write-sexp (sexp)
<syntaxhighlight lang="lisp">(defun write-sexp (sexp)
"Writes a Lisp s-expression in square bracket notation."
"Writes a Lisp s-expression in square bracket notation."
(labels ((parse (sexp)
(labels ((parse (sexp)
Line 2,127: Line 2,127:
(subseq str 0 last-char)
(subseq str 0 last-char)
str)))))))
str)))))))
(concatenate 'string "[" (fix-spacing (parse sexp)) "]")))</lang>
(concatenate 'string "[" (fix-spacing (parse sexp)) "]")))</syntaxhighlight>
Unit test code:
Unit test code:
<lang lisp>(setf unit-tests '(((1 2) (3 4)) (1 2 3 4) ("ab(cd" "mn)op")
<syntaxhighlight lang="lisp">(setf unit-tests '(((1 2) (3 4)) (1 2 3 4) ("ab(cd" "mn)op")
(1 (2 (3 (4)))) ((1) (2) (3)) ()))
(1 (2 (3 (4)))) ((1) (2) (3)) ()))


Line 2,135: Line 2,135:
(dolist (test unit-tests)
(dolist (test unit-tests)
(format t "Before: ~18s After: ~s~%"
(format t "Before: ~18s After: ~s~%"
test (write-sexp test))))</lang>
test (write-sexp test))))</syntaxhighlight>
{{out|Unit test output}}
{{out|Unit test output}}
<pre>CL-USER> (run-tests)
<pre>CL-USER> (run-tests)
Line 2,161: Line 2,161:
a native floating point type, floating point numbers are not.
a native floating point type, floating point numbers are not.


<lang cowgol>include "cowgol.coh";
<syntaxhighlight lang="cowgol">include "cowgol.coh";
include "strings.coh";
include "strings.coh";
include "malloc.coh";
include "malloc.coh";
Line 2,426: Line 2,426:
print("Parsed:\n");
print("Parsed:\n");
prettyprint(ParseSExp(str));
prettyprint(ParseSExp(str));
print_nl();</lang>
print_nl();</syntaxhighlight>


{{out}}
{{out}}
Line 2,455: Line 2,455:


=={{header|D}}==
=={{header|D}}==
<lang d>import std.stdio, std.conv, std.algorithm, std.variant, std.uni,
<syntaxhighlight lang="d">import std.stdio, std.conv, std.algorithm, std.variant, std.uni,
std.functional, std.string;
std.functional, std.string;


Line 2,541: Line 2,541:
"Printed: ".write;
"Printed: ".write;
pTest.writeSexp;
pTest.writeSexp;
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>Parsed: [[data, quoted data, 123, 4.5], [data, [!@#, [4.5], (more, data)]]]
<pre>Parsed: [[data, quoted data, 123, 4.5], [data, [!@#, [4.5], (more, data)]]]
Line 2,548: Line 2,548:
=={{header|EchoLisp}}==
=={{header|EchoLisp}}==
The '''(read-from-string input-string)''' function parses a string into an s-expression, which is the native representation of program/data in EchoLisp and the majority of Lisps .
The '''(read-from-string input-string)''' function parses a string into an s-expression, which is the native representation of program/data in EchoLisp and the majority of Lisps .
<lang lisp>
<syntaxhighlight lang="lisp">
(define input-string #'((data "quoted data" 123 4.5)\n(data (!@# (4.5) "(more" "data)")))'#)
(define input-string #'((data "quoted data" 123 4.5)\n(data (!@# (4.5) "(more" "data)")))'#)


Line 2,565: Line 2,565:
(first(rest s-expr))
(first(rest s-expr))
→ (data (!@# (4.5) "(more" "data)"))
→ (data (!@# (4.5) "(more" "data)"))
</syntaxhighlight>
</lang>


=={{header|F_Sharp|F#}}==
=={{header|F_Sharp|F#}}==
Line 2,578: Line 2,578:
The file <code>SExpr.fs</code> containing the implementation:
The file <code>SExpr.fs</code> containing the implementation:


<lang fsharp>
<syntaxhighlight lang="fsharp">
module SExpr
module SExpr
(* This module is a very simple port of the OCaml version to F# (F-Sharp) *)
(* This module is a very simple port of the OCaml version to F# (F-Sharp) *)
Line 2,810: Line 2,810:
(* print_endline (string_of_sexpr_indent s) *)
(* print_endline (string_of_sexpr_indent s) *)
printfn "%s" (string_of_sexpr_indent s)
printfn "%s" (string_of_sexpr_indent s)
</syntaxhighlight>
</lang>




Line 2,817: Line 2,817:
Read the experession from a file of preset it in the code.
Read the experession from a file of preset it in the code.


<lang fsharp>
<syntaxhighlight lang="fsharp">
module Program
module Program
(* Learn more about F# at https://fsharp.org *)
(* Learn more about F# at https://fsharp.org *)
Line 2,855: Line 2,855:
(* return an integer exit code *)
(* return an integer exit code *)
0
0
</syntaxhighlight>
</lang>


{{out}}
{{out}}
Line 2,881: Line 2,881:
Factor has a comprehensive prettyprinter which can print any Factor object in a readable way. Not only can we leverage it to easily print our native data structure, but we can also call <code>unparse</code> to convert it to a string. This leaves us with a string reminiscent of the original input, and we are able to take it the rest of the way with two simple regular expressions.
Factor has a comprehensive prettyprinter which can print any Factor object in a readable way. Not only can we leverage it to easily print our native data structure, but we can also call <code>unparse</code> to convert it to a string. This leaves us with a string reminiscent of the original input, and we are able to take it the rest of the way with two simple regular expressions.


<lang factor>USING: formatting kernel math.parser multiline peg peg.ebnf
<syntaxhighlight lang="factor">USING: formatting kernel math.parser multiline peg peg.ebnf
regexp sequences prettyprint words ;
regexp sequences prettyprint words ;
IN: rosetta-code.s-expressions
IN: rosetta-code.s-expressions
Line 2,907: Line 2,907:
sexp>seq dup seq>sexp
sexp>seq dup seq>sexp
"Native:\n%u\n\nRound trip:\n%s\n" printf
"Native:\n%u\n\nRound trip:\n%s\n" printf
] bi</lang>
] bi</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 2,926: Line 2,926:


=={{header|Go}}==
=={{header|Go}}==
<lang go>package main
<syntaxhighlight lang="go">package main


import (
import (
Line 3,099: Line 3,099:
fmt.Println(s.i)
fmt.Println(s.i)
}
}
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 3,127: Line 3,127:


=={{header|Haskell}}==
=={{header|Haskell}}==
<lang haskell>import qualified Data.Functor.Identity as F
<syntaxhighlight lang="haskell">import qualified Data.Functor.Identity as F
import qualified Text.Parsec.Prim as Prim
import qualified Text.Parsec.Prim as Prim
import Text.Parsec
import Text.Parsec
Line 3,166: Line 3,166:
"((data \"quoted data\" 123 4.5)\n (data (!@# (4.5) \"(more\" \"data)\")))"
"((data \"quoted data\" 123 4.5)\n (data (!@# (4.5) \"(more\" \"data)\")))"
putStrLn ("The input:\n" ++ expr ++ "\n\nParsed as:")
putStrLn ("The input:\n" ++ expr ++ "\n\nParsed as:")
p expr</lang>
p expr</syntaxhighlight>
{{Out}}
{{Out}}
<pre>The input:
<pre>The input:
Line 3,177: Line 3,177:


Or, parsing by hand (rather than with a parser combinator library) and printing a parse tree diagram:
Or, parsing by hand (rather than with a parser combinator library) and printing a parse tree diagram:
<lang haskell>{-# LANGUAGE TupleSections #-}
<syntaxhighlight lang="haskell">{-# LANGUAGE TupleSections #-}
import Data.Bifunctor (bimap)
import Data.Bifunctor (bimap)
Line 3,294: Line 3,294:
headDef :: a -> [a] -> a
headDef :: a -> [a] -> a
headDef d [] = d
headDef d [] = d
headDef _ (x : _) = x</lang>
headDef _ (x : _) = x</syntaxhighlight>
{{Out}}
{{Out}}
<pre>Symbol "List"
<pre>Symbol "List"
Line 3,335: Line 3,335:
The example takes single and double quotes. <br>
The example takes single and double quotes. <br>
Single quotes were used instead of doubles in the input.
Single quotes were used instead of doubles in the input.
<lang Icon>link ximage
<syntaxhighlight lang="icon">link ximage


procedure main()
procedure main()
Line 3,394: Line 3,394:
}
}
return T
return T
end</lang>
end</syntaxhighlight>


{{libheader|Icon Programming Library}}
{{libheader|Icon Programming Library}}
Line 3,425: Line 3,425:
This implementation does not support escape characters. If escape characters were added, we would need additional support in the tokenizer (an extra character class, and in the state table an extra column and two extra rows, or almost double the number of state transitions: 35 instead of 20), and additional support in the data language (unfmt would need to strip out escape characters and fmt would need to insert escape characters -- so each of these routines would also perhaps double in size.) And that's a lot of bulk for serialize/deserialize mechanism which, by design, cannot represent frequently used data elements (such as matrices and gerunds).
This implementation does not support escape characters. If escape characters were added, we would need additional support in the tokenizer (an extra character class, and in the state table an extra column and two extra rows, or almost double the number of state transitions: 35 instead of 20), and additional support in the data language (unfmt would need to strip out escape characters and fmt would need to insert escape characters -- so each of these routines would also perhaps double in size.) And that's a lot of bulk for serialize/deserialize mechanism which, by design, cannot represent frequently used data elements (such as matrices and gerunds).


<lang j>NB. character classes: 0: paren, 1: quote, 2: whitespace, 3: wordforming (default)
<syntaxhighlight lang="j">NB. character classes: 0: paren, 1: quote, 2: whitespace, 3: wordforming (default)
chrMap=: '()';'"';' ',LF,TAB,CR
chrMap=: '()';'"';' ',LF,TAB,CR


Line 3,476: Line 3,476:


readSexpr=: fmt L:0 @rdSexpr :.writeSexpr
readSexpr=: fmt L:0 @rdSexpr :.writeSexpr
writeSexpr=: wrSexpr @(unfmt L:0) :.readSexpr</lang>
writeSexpr=: wrSexpr @(unfmt L:0) :.readSexpr</syntaxhighlight>




Example use:
Example use:


<lang j> readSexpr '((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))'
<syntaxhighlight lang="j"> readSexpr '((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))'
┌───────────────────────────┬────────────────────────────────┐
┌───────────────────────────┬────────────────────────────────┐
│┌─────┬───────────┬───┬───┐│┌─────┬────────────────────────┐│
│┌─────┬───────────┬───┬───┐│┌─────┬────────────────────────┐│
Line 3,492: Line 3,492:
└───────────────────────────┴────────────────────────────────┘
└───────────────────────────┴────────────────────────────────┘
writeSexpr readSexpr '((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))'
writeSexpr readSexpr '((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))'
((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))</lang>
((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))</syntaxhighlight>


=={{header|Java}}==
=={{header|Java}}==
Line 3,502: Line 3,502:


====LispTokenizer.java====
====LispTokenizer.java====
<lang java>package jfkbits;
<syntaxhighlight lang="java">package jfkbits;


import java.io.BufferedReader;
import java.io.BufferedReader;
Line 3,612: Line 3,612:
{
{
}
}
}</lang>
}</syntaxhighlight>


====Token.java====
====Token.java====
<lang java>package jfkbits;
<syntaxhighlight lang="java">package jfkbits;
import java.io.StreamTokenizer;
import java.io.StreamTokenizer;


Line 3,643: Line 3,643:
}
}
}
}
}</lang>
}</syntaxhighlight>


====Atom.java====
====Atom.java====
<lang java>package jfkbits;
<syntaxhighlight lang="java">package jfkbits;


import jfkbits.LispParser.Expr;
import jfkbits.LispParser.Expr;
Line 3,662: Line 3,662:
}
}


}</lang>
}</syntaxhighlight>


====StringAtom.java====
====StringAtom.java====
<lang java>package jfkbits;
<syntaxhighlight lang="java">package jfkbits;


public class StringAtom extends Atom
public class StringAtom extends Atom
Line 3,685: Line 3,685:
}
}
}
}
</syntaxhighlight>
</lang>


====ExprList.java====
====ExprList.java====
<lang java>package jfkbits;
<syntaxhighlight lang="java">package jfkbits;


import java.util.AbstractCollection;
import java.util.AbstractCollection;
Line 3,758: Line 3,758:
}
}


}</lang>
}</syntaxhighlight>


====LispParser.java====
====LispParser.java====
<lang java>package jfkbits;
<syntaxhighlight lang="java">package jfkbits;




Line 3,808: Line 3,808:


}
}
</syntaxhighlight>
</lang>


====LispParserDemo.java====
====LispParserDemo.java====
<lang java>import jfkbits.ExprList;
<syntaxhighlight lang="java">import jfkbits.ExprList;
import jfkbits.LispParser;
import jfkbits.LispParser;
import jfkbits.LispParser.ParseException;
import jfkbits.LispParser.ParseException;
Line 3,836: Line 3,836:
}
}
}
}
}</lang>
}</syntaxhighlight>


=={{header|JavaScript}}==
=={{header|JavaScript}}==
===Procedural===
===Procedural===
<lang JavaScript>String.prototype.parseSexpr = function() {
<syntaxhighlight lang="javascript">String.prototype.parseSexpr = function() {
var t = this.match(/\s*("[^"]*"|\(|\)|"|[^\s()"]+)/g)
var t = this.match(/\s*("[^"]*"|\(|\)|"|[^\s()"]+)/g)
for (var o, c=0, i=t.length-1; i>=0; i--) {
for (var o, c=0, i=t.length-1; i>=0; i--) {
Line 3,877: Line 3,877:
document.write('Invalid s-expr!', '<br>')
document.write('Invalid s-expr!', '<br>')
else
else
document.write('s-expr:<br>', sexpr, '<br><br>', sexpr.constructor != Array ? '' : 'pretty print:<br>' + sexpr.toPretty())</lang>
document.write('s-expr:<br>', sexpr, '<br><br>', sexpr.constructor != Array ? '' : 'pretty print:<br>' + sexpr.toPretty())</syntaxhighlight>
{{out}}
{{out}}
<pre>text:
<pre>text:
Line 3,910: Line 3,910:
===Functional===
===Functional===
Showing the parse tree in an indented JSON format, and writing out a reserialization:
Showing the parse tree in an indented JSON format, and writing out a reserialization:
<lang JavaScript>(() => {
<syntaxhighlight lang="javascript">(() => {
"use strict";
"use strict";


Line 4,047: Line 4,047:


return main();
return main();
})();</lang>
})();</syntaxhighlight>
{{Out}}
{{Out}}
<pre>[
<pre>[
Line 4,082: Line 4,082:


=={{header|Julia}}==
=={{header|Julia}}==
<lang julia>
<syntaxhighlight lang="julia">
function rewritequotedparen(s)
function rewritequotedparen(s)
segments = split(s, "\"")
segments = split(s, "\"")
Line 4,157: Line 4,157:
println("The processed native structure is:\n", nat)
println("The processed native structure is:\n", nat)
println("The reconstructed string is:\n"), printAny(nat)
println("The reconstructed string is:\n"), printAny(nat)
</syntaxhighlight>
</lang>
{{output}}<pre>
{{output}}<pre>
The input string is:
The input string is:
Line 4,173: Line 4,173:
=={{header|Kotlin}}==
=={{header|Kotlin}}==
{{trans|JavaScript}}
{{trans|JavaScript}}
<lang groovy>// version 1.2.31
<syntaxhighlight lang="groovy">// version 1.2.31


const val INDENT = 2
const val INDENT = 2
Line 4,270: Line 4,270:
tokens2.prettyPrint()
tokens2.prettyPrint()
}
}
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 4,328: Line 4,328:
Tested with Lua 5.3.5 and LPeg 1.0.2-1.
Tested with Lua 5.3.5 and LPeg 1.0.2-1.


<lang lua>lpeg = require 'lpeg' -- see http://www.inf.puc-rio.br/~roberto/lpeg/
<syntaxhighlight lang="lua">lpeg = require 'lpeg' -- see http://www.inf.puc-rio.br/~roberto/lpeg/


imports = 'P R S C V match'
imports = 'P R S C V match'
Line 4,354: Line 4,354:
'S';
'S';
S = ws * lpar * C((atom + V'S')^0) * rpar / tolist
S = ws * lpar * C((atom + V'S')^0) * rpar / tolist
}</lang>
}</syntaxhighlight>


Now to use the <i>sexpr</i> pattern:
Now to use the <i>sexpr</i> pattern:


<lang lua>eg_input = [[
<syntaxhighlight lang="lua">eg_input = [[
((data "quoted data" 123 4.5)
((data "quoted data" 123 4.5)
(data (!@# (4.5) "(more" "data)")))
(data (!@# (4.5) "(more" "data)")))
Line 4,382: Line 4,382:
check(eg_produced, eg_expected)
check(eg_produced, eg_expected)
print("checks out!") -- won't get here if any <i>check()</i> assertion fails
print("checks out!") -- won't get here if any <i>check()</i> assertion fails
</syntaxhighlight>
</lang>


And here's the pretty printer, whose output looks like all the others:
And here's the pretty printer, whose output looks like all the others:


<lang lua>function pprint(expr, indent)
<syntaxhighlight lang="lua">function pprint(expr, indent)
local function prindent(fmt, expr)
local function prindent(fmt, expr)
io.write(indent) -- no line break
io.write(indent) -- no line break
Line 4,411: Line 4,411:
end
end


pprint(eg_expected, '')</lang>
pprint(eg_expected, '')</syntaxhighlight>


=={{header|Nim}}==
=={{header|Nim}}==


<lang nim>import strutils
<syntaxhighlight lang="nim">import strutils


const Input = """
const Input = """
Line 4,559: Line 4,559:
else: nil
else: nil


echo parse()</lang>
echo parse()</syntaxhighlight>


{{out}}
{{out}}
Line 4,576: Line 4,576:
The file <code>SExpr.mli</code> containing the interface:
The file <code>SExpr.mli</code> containing the interface:


<lang ocaml>(** This module is a very simple parsing library for S-expressions. *)
<syntaxhighlight lang="ocaml">(** This module is a very simple parsing library for S-expressions. *)
(* Copyright (C) 2009 Florent Monnier, released under MIT license. *)
(* Copyright (C) 2009 Florent Monnier, released under MIT license. *)


Line 4,604: Line 4,604:


val string_of_sexpr_indent : sexpr list -> string
val string_of_sexpr_indent : sexpr list -> string
(** same than [string_of_sexpr] but with indentation *)</lang>
(** same than [string_of_sexpr] but with indentation *)</syntaxhighlight>


The file <code>SExpr.ml</code> containing the implementation:
The file <code>SExpr.ml</code> containing the implementation:


<lang ocaml>(** This module is a very simple parsing library for S-expressions. *)
<syntaxhighlight lang="ocaml">(** This module is a very simple parsing library for S-expressions. *)
(* Copyright (C) 2009 Florent Monnier, released under MIT license. *)
(* Copyright (C) 2009 Florent Monnier, released under MIT license. *)
(* modified to match the task description *)
(* modified to match the task description *)
Line 4,785: Line 4,785:


let print_sexpr_indent s =
let print_sexpr_indent s =
print_endline (string_of_sexpr_indent s)</lang>
print_endline (string_of_sexpr_indent s)</syntaxhighlight>


Then we compile this small module and test it in the interactive loop:
Then we compile this small module and test it in the interactive loop:
Line 4,823: Line 4,823:


=={{header|Perl}}==
=={{header|Perl}}==
<lang perl>#!/usr/bin/perl -w
<syntaxhighlight lang="perl">#!/usr/bin/perl -w
use strict;
use strict;
use warnings;
use warnings;
Line 4,877: Line 4,877:
ref($_) eq 'ARRAY' ? sexpr2txt($_) : $$_
ref($_) eq 'ARRAY' ? sexpr2txt($_) : $$_
} @{$_[0]} ]})}
} @{$_[0]} ]})}
}</lang>
}</syntaxhighlight>
Check:
Check:
<lang perl>my $s = sexpr(q{
<syntaxhighlight lang="perl">my $s = sexpr(q{


((data "quoted data" 123 4.5)
((data "quoted data" 123 4.5)
Line 4,891: Line 4,891:


# Convert back
# Convert back
print sexpr2txt($s)."\n";</lang>
print sexpr2txt($s)."\n";</syntaxhighlight>
Output:
Output:
<pre>$VAR1 = [
<pre>$VAR1 = [
Line 4,920: Line 4,920:
that may not be clear on the display: 4e-5 and 4-e5 may appear similar but the latter is probably a parse failure. It may
that may not be clear on the display: 4e-5 and 4-e5 may appear similar but the latter is probably a parse failure. It may
be more sensible for get_term() to raise an error if the scanf fails, than assume it is a symbol like it does now.
be more sensible for get_term() to raise an error if the scanf fails, than assume it is a symbol like it does now.
<!--<lang Phix>(phixonline)-->
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">s_expr_str</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"""
<span style="color: #008080;">constant</span> <span style="color: #000000;">s_expr_str</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"""
Line 5,006: Line 5,006:
<span style="color: #000080;font-style:italic;">--ppEx(s_expr,{pp_Nest,1,pp_StrFmt,-1,pp_IntCh,false,pp_Brkt,"()"})</span>
<span style="color: #000080;font-style:italic;">--ppEx(s_expr,{pp_Nest,1,pp_StrFmt,-1,pp_IntCh,false,pp_Brkt,"()"})</span>
<span style="color: #7060A8;">ppEx</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s_expr</span><span style="color: #0000FF;">,{</span><span style="color: #004600;">pp_Nest</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #004600;">pp_StrFmt</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #004600;">pp_IntCh</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">,</span><span style="color: #004600;">pp_Brkt</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"()"</span><span style="color: #0000FF;">})</span>
<span style="color: #7060A8;">ppEx</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s_expr</span><span style="color: #0000FF;">,{</span><span style="color: #004600;">pp_Nest</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #004600;">pp_StrFmt</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #004600;">pp_IntCh</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">,</span><span style="color: #004600;">pp_Brkt</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"()"</span><span style="color: #0000FF;">})</span>
<!--</lang>-->
<!--</syntaxhighlight>-->
{{out}}
{{out}}
<pre>
<pre>
Line 5,030: Line 5,030:
=={{header|PicoLisp}}==
=={{header|PicoLisp}}==
The '[http://software-lab.de/doc/refA.html#any any]' function parses an s-expression from a string (indentical to the way '[http://software-lab.de/doc/refR.html#read read]' does this from an input stream).
The '[http://software-lab.de/doc/refA.html#any any]' function parses an s-expression from a string (indentical to the way '[http://software-lab.de/doc/refR.html#read read]' does this from an input stream).
<lang PicoLisp>: (any "((data \"quoted data\" 123 4.5) (data (!@# (4.5) \"(more\" \"data)\")))")
<syntaxhighlight lang="picolisp">: (any "((data \"quoted data\" 123 4.5) (data (!@# (4.5) \"(more\" \"data)\")))")
-> ((data "quoted data" 123 5) (data (!@# (5) "(more" "data)")))
-> ((data "quoted data" 123 5) (data (!@# (5) "(more" "data)")))


Line 5,050: Line 5,050:
+-- "(more"
+-- "(more"
|
|
+-- "data)"</lang>
+-- "data)"</syntaxhighlight>
Implementing a subset of 'any' explicitly:
Implementing a subset of 'any' explicitly:
<lang PicoLisp>(de readSexpr ()
<syntaxhighlight lang="picolisp">(de readSexpr ()
(case (skip)
(case (skip)
("(" (char) (readList))
("(" (char) (readList))
Line 5,077: Line 5,077:
(until (or (sp? (peek)) (member (peek) '("(" ")")))
(until (or (sp? (peek)) (member (peek) '("(" ")")))
(link (char)) ) )
(link (char)) ) )
(or (format X) (intern (pack X))) ) )</lang>
(or (format X) (intern (pack X))) ) )</syntaxhighlight>
It can be used in a pipe to read from a string:
It can be used in a pipe to read from a string:
<lang PicoLisp>: (pipe (prin "((data \"quoted data\" 123 4.5) (data (!@# (4.5) \"(more\" \"data)\")))") (readSexpr))
<syntaxhighlight lang="picolisp">: (pipe (prin "((data \"quoted data\" 123 4.5) (data (!@# (4.5) \"(more\" \"data)\")))") (readSexpr))
-> ((data "quoted data" 123 5) (data (!@# (5) "(more" "data)")))</lang>
-> ((data "quoted data" 123 5) (data (!@# (5) "(more" "data)")))</syntaxhighlight>
'[http://software-lab.de/doc/refS.html#sym sym]' does the reverse (i.e. builds a symbol (string) from an expression).
'[http://software-lab.de/doc/refS.html#sym sym]' does the reverse (i.e. builds a symbol (string) from an expression).
<lang PicoLisp>: (sym @@)
<syntaxhighlight lang="picolisp">: (sym @@)
-> "((data \"quoted data\" 123 5) (data (!@# (5) \"(more\" \"data)\")))"</lang>
-> "((data \"quoted data\" 123 5) (data (!@# (5) \"(more\" \"data)\")))"</syntaxhighlight>
Implementing a subset of the built-in printer:
Implementing a subset of the built-in printer:
<lang PicoLisp>(de printSexpr (Expr Fun)
<syntaxhighlight lang="picolisp">(de printSexpr (Expr Fun)
(cond
(cond
((pair Expr)
((pair Expr)
Line 5,098: Line 5,098:
(mapc Fun (chop Expr))
(mapc Fun (chop Expr))
(Fun "\"") )
(Fun "\"") )
(T (mapc Fun (chop Expr))) ) )</lang>
(T (mapc Fun (chop Expr))) ) )</syntaxhighlight>
This can be used for plain printing
This can be used for plain printing
<lang PicoLisp>: (printSexpr
<syntaxhighlight lang="picolisp">: (printSexpr
'((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))
'((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))
prin )
prin )
((data "quoted data" 123 5) (data (!@# (5) "(more" "data)")))</lang>
((data "quoted data" 123 5) (data (!@# (5) "(more" "data)")))</syntaxhighlight>
or to collect the characters into a string:
or to collect the characters into a string:
<lang PicoLisp>: (pack
<syntaxhighlight lang="picolisp">: (pack
(make
(make
(printSexpr
(printSexpr
'((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))
'((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))
link ) ) )
link ) ) )
-> "((data \"quoted data\" 123 5) (data (!@# (5) \"(more\" \"data)\")))"</lang>
-> "((data \"quoted data\" 123 5) (data (!@# (5) \"(more\" \"data)\")))"</syntaxhighlight>


=={{header|Pike}}==
=={{header|Pike}}==
<lang pike>class Symbol(string name)
<syntaxhighlight lang="pike">class Symbol(string name)
{
{
string _sprintf(int type)
string _sprintf(int type)
Line 5,218: Line 5,218:
string input = "((data \"quoted data\" 123 4.5)\n (data (!@# (4.5) \"(more\" \"data)\")))";
string input = "((data \"quoted data\" 123 4.5)\n (data (!@# (4.5) \"(more\" \"data)\")))";
array data = group(tokenizer(input))[0];
array data = group(tokenizer(input))[0];
string output = sexp(data);</lang>
string output = sexp(data);</syntaxhighlight>


Output:
Output:
Line 5,230: Line 5,230:
=={{header|Potion}}==
=={{header|Potion}}==
How values are stored: Tuples for list, integers for integers, floats for floats, strings for symbols, quoted strings for strings. This implementation is not the most elegant/succinct or practical (it's trusty and has no real error handling).
How values are stored: Tuples for list, integers for integers, floats for floats, strings for symbols, quoted strings for strings. This implementation is not the most elegant/succinct or practical (it's trusty and has no real error handling).
<lang potion>isdigit = (c): 47 < c ord and c ord < 58.
<syntaxhighlight lang="potion">isdigit = (c): 47 < c ord and c ord < 58.
iswhitespace = (c): c ord == 10 or c ord == 13 or c == " ".
iswhitespace = (c): c ord == 10 or c ord == 13 or c == " ".


Line 5,301: Line 5,301:
parsesexpr("((data \"quoted data\" 123 4.5)
parsesexpr("((data \"quoted data\" 123 4.5)
(data (!@# (4.5) \"(more\" \"data)\")))") string print
(data (!@# (4.5) \"(more\" \"data)\")))") string print
"\n" print</lang>
"\n" print</syntaxhighlight>


=={{header|Python}}==
=={{header|Python}}==
===Procedural===
===Procedural===
<lang python>import re
<syntaxhighlight lang="python">import re


dbg = False
dbg = False
Line 5,364: Line 5,364:
print("\nParsed to Python:", parsed)
print("\nParsed to Python:", parsed)


print("\nThen back to: '%s'" % print_sexp(parsed))</lang>
print("\nThen back to: '%s'" % print_sexp(parsed))</syntaxhighlight>


;Output:
;Output:
Line 5,375: Line 5,375:
;Simpler parser:
;Simpler parser:
Note that in the example above the parser also recognises and changes the type of some tokens as well as generating a nested list. If that functionality is not needed, or better done elsewhere, then the parse function can be achieved more simply by just applying the regexp:
Note that in the example above the parser also recognises and changes the type of some tokens as well as generating a nested list. If that functionality is not needed, or better done elsewhere, then the parse function can be achieved more simply by just applying the regexp:
<lang python>>>> from pprint import pprint as pp
<syntaxhighlight lang="python">>>> from pprint import pprint as pp
>>> x = [[(t,v) for t,v in termtypes.groupdict().items() if v][0] for termtypes in re.finditer(term_regex, sexp)]
>>> x = [[(t,v) for t,v in termtypes.groupdict().items() if v][0] for termtypes in re.finditer(term_regex, sexp)]
>>> pp(x)
>>> pp(x)
Line 5,397: Line 5,397:
('brackr', ')'),
('brackr', ')'),
('brackr', ')')]
('brackr', ')')]
>>> </lang>
>>> </syntaxhighlight>


===Functional===
===Functional===
Composing functionally, and writing out a tree diagram, and a serialization, of the parse.
Composing functionally, and writing out a tree diagram, and a serialization, of the parse.
<lang python>'''S-expressions'''
<syntaxhighlight lang="python">'''S-expressions'''


from itertools import chain, repeat
from itertools import chain, repeat
Line 5,648: Line 5,648:
# MAIN ---
# MAIN ---
if __name__ == '__main__':
if __name__ == '__main__':
main()</lang>
main()</syntaxhighlight>
{{Out}}
{{Out}}
<pre>{'name': 'List'}
<pre>{'name': 'List'}
Line 5,685: Line 5,685:


Racket has builtin support for S-expressions in the form of the read function.
Racket has builtin support for S-expressions in the form of the read function.
<lang racket>
<syntaxhighlight lang="racket">
#lang racket
#lang racket
(define input
(define input
Line 5,695: Line 5,695:


(read (open-input-string input))
(read (open-input-string input))
</syntaxhighlight>
</lang>
Output:
Output:
<pre>
<pre>
Line 5,707: Line 5,707:
This parses the task, but it isn't really a good lisp parser, because it always wants whitespace between lists, so <code>(()())</code> will fail ( <code>(() ())</code> wont)
This parses the task, but it isn't really a good lisp parser, because it always wants whitespace between lists, so <code>(()())</code> will fail ( <code>(() ())</code> wont)


<lang perl6>grammar S-Exp {
<syntaxhighlight lang="raku" line>grammar S-Exp {
rule TOP {^ <s-list> $};
rule TOP {^ <s-list> $};


Line 5,749: Line 5,749:
say "the expression:\n$s-exp\n";
say "the expression:\n$s-exp\n";
say "the Raku expression:\n{$raku_array.raku}\n";
say "the Raku expression:\n{$raku_array.raku}\n";
say "and back:\n{s-exp_writer($raku_array)}";</lang>
say "and back:\n{s-exp_writer($raku_array)}";</syntaxhighlight>


{{out}}
{{out}}
Line 5,769: Line 5,769:


It would normally be considered improper, but the literal string delimiters were left intact; making it much easier to understand what is/was being parsed.
It would normally be considered improper, but the literal string delimiters were left intact; making it much easier to understand what is/was being parsed.
<lang rexx>/*REXX program parses an S-expression and displays the results to the terminal. */
<syntaxhighlight lang="rexx">/*REXX program parses an S-expression and displays the results to the terminal. */
input= '((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))'
input= '((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))'
say center('input', length(input), "═") /*display the header title to terminal.*/
say center('input', length(input), "═") /*display the header title to terminal.*/
Line 5,824: Line 5,824:
exit 0 /*stick a fork in it, we're all done. */
exit 0 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
add!: if !='' then return; #=#+1; @.#=left("", max(0, tabs*(level-1)))!; !=; return</lang>
add!: if !='' then return; #=#+1; @.#=left("", max(0, tabs*(level-1)))!; !=; return</syntaxhighlight>
{{out|output|text=&nbsp; when using the default input:}}
{{out|output|text=&nbsp; when using the default input:}}
<pre>
<pre>
Line 5,853: Line 5,853:
=={{header|Ruby}}==
=={{header|Ruby}}==
{{works with|Ruby|1.9}}
{{works with|Ruby|1.9}}
<lang ruby>class SExpr
<syntaxhighlight lang="ruby">class SExpr
def initialize(str)
def initialize(str)
@original = str
@original = str
Line 5,974: Line 5,974:
puts "original sexpr:\n#{sexpr.original}"
puts "original sexpr:\n#{sexpr.original}"
puts "\nruby data structure:\n#{sexpr.data}"
puts "\nruby data structure:\n#{sexpr.data}"
puts "\nand back to S-Expr:\n#{sexpr.to_sexpr}"</lang>
puts "\nand back to S-Expr:\n#{sexpr.to_sexpr}"</syntaxhighlight>


{{out}}
{{out}}
Line 5,991: Line 5,991:
=={{header|Rust}}==
=={{header|Rust}}==
lib.rs:
lib.rs:
<lang rust>
<syntaxhighlight lang="rust">
//! This implementation isn't based on anything in particular, although it's probably informed by a
//! This implementation isn't based on anything in particular, although it's probably informed by a
//! lot of Rust's JSON encoding code. It should be very fast (both encoding and decoding the toy
//! lot of Rust's JSON encoding code. It should be very fast (both encoding and decoding the toy
Line 6,382: Line 6,382:
println!("{:?}", SExp::parse(ctx));
println!("{:?}", SExp::parse(ctx));
}
}
</lang>{{out}}
</syntaxhighlight>{{out}}
<pre>
<pre>
Ok("((\"data\" \"quoted data\" 123 4.5) (\"data\" (\"!@#\" (4.5) \"(more\" \"data)\")))")
Ok("((\"data\" \"quoted data\" 123 4.5) (\"data\" (\"!@#\" (4.5) \"(more\" \"data)\")))")
Line 6,399: Line 6,399:
Using guile scheme 2.0.11
Using guile scheme 2.0.11


<lang scheme>(define (sexpr-read port)
<syntaxhighlight lang="scheme">(define (sexpr-read port)
(define (help port)
(define (help port)
(let ((char (read-char port)))
(let ((char (read-char port)))
Line 6,442: Line 6,442:


(format-sexpr (sexpr-read
(format-sexpr (sexpr-read
(open-input-string "((data \"quoted data\" 123 4.5) (data (!@# (4.5) \"(more\" \"data)\")))")))</lang>
(open-input-string "((data \"quoted data\" 123 4.5) (data (!@# (4.5) \"(more\" \"data)\")))")))</syntaxhighlight>


Output:
Output:
Line 6,467: Line 6,467:
=={{header|Sidef}}==
=={{header|Sidef}}==
{{trans|Perl}}
{{trans|Perl}}
<lang ruby>func sexpr(txt) {
<syntaxhighlight lang="ruby">func sexpr(txt) {
txt.trim!
txt.trim!


Line 6,516: Line 6,516:


say s # dump structure
say s # dump structure
say sexpr2txt(s) # convert back</lang>
say sexpr2txt(s) # convert back</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 6,525: Line 6,525:
=={{header|Tcl}}==
=={{header|Tcl}}==
Note that because Tcl doesn't expose a type system (well, not in a conventional sense) the parts of the parsed out data structure are tagged lists; the first element is one of “<tt>string</tt>”, “<tt>int</tt>”, “<tt>real</tt>” and “<tt>atom</tt>” to indicate a leaf token, or “<tt>list</tt>” to indicate a sublist. A “native” data structure could also be generated, but then that would turn things into lists that are not in the original.
Note that because Tcl doesn't expose a type system (well, not in a conventional sense) the parts of the parsed out data structure are tagged lists; the first element is one of “<tt>string</tt>”, “<tt>int</tt>”, “<tt>real</tt>” and “<tt>atom</tt>” to indicate a leaf token, or “<tt>list</tt>” to indicate a sublist. A “native” data structure could also be generated, but then that would turn things into lists that are not in the original.
<lang tcl>package require Tcl 8.5
<syntaxhighlight lang="tcl">package require Tcl 8.5


proc fromSexp {str} {
proc fromSexp {str} {
Line 6,573: Line 6,573:
return [lindex $content 0]
return [lindex $content 0]
}
}
}</lang>
}</syntaxhighlight>
Demonstrating with the sample data:
Demonstrating with the sample data:
<lang tcl>set sample {((data "quoted data" 123 4.5)
<syntaxhighlight lang="tcl">set sample {((data "quoted data" 123 4.5)
(data (!@# (4.5) "(more" "data)")))}
(data (!@# (4.5) "(more" "data)")))}
set parsed [fromSexp $sample]
set parsed [fromSexp $sample]
puts "sample: $sample"
puts "sample: $sample"
puts "parsed: $parsed"
puts "parsed: $parsed"
puts "regen: [toSexp $parsed]"</lang>
puts "regen: [toSexp $parsed]"</syntaxhighlight>
Output:
Output:
<pre>
<pre>
Line 6,626: Line 6,626:
Code:
Code:


<lang txr>@(define float (f))@\
<syntaxhighlight lang="txr">@(define float (f))@\
@(local (tok))@\
@(local (tok))@\
@(cases)@\
@(cases)@\
Line 6,669: Line 6,669:
expr: @(format nil "~s" e)
expr: @(format nil "~s" e)
junk: @junk
junk: @junk
@(end)</lang>
@(end)</syntaxhighlight>


Run:
Run:
Line 6,704: Line 6,704:
Explanation of most confusing line:
Explanation of most confusing line:


<lang txr> @/\s*\(\s*/@(coll :vars (e))@(expr e)@/\s*/@(last))@(end)</lang>
<syntaxhighlight lang="txr"> @/\s*\(\s*/@(coll :vars (e))@(expr e)@/\s*/@(last))@(end)</syntaxhighlight>


First, we match an open parenthesis that can be embedded in whitespace. Then we have a <code>@(coll)</code> construct which terminates with <code>@(end)</code>. This is a repetition construct for collecting zero or more items. The <code>:vars (e)</code> argument makes the collect strict: each repetition must bind the variable <code>e</code>. More importantly, in this case, if nothing is
First, we match an open parenthesis that can be embedded in whitespace. Then we have a <code>@(coll)</code> construct which terminates with <code>@(end)</code>. This is a repetition construct for collecting zero or more items. The <code>:vars (e)</code> argument makes the collect strict: each repetition must bind the variable <code>e</code>. More importantly, in this case, if nothing is
Line 6,713: Line 6,713:
{{libheader|Wren-pattern}}
{{libheader|Wren-pattern}}
{{libheader|Wren-fmt}}
{{libheader|Wren-fmt}}
<lang ecmascript>import "/pattern" for Pattern
<syntaxhighlight lang="ecmascript">import "/pattern" for Pattern
import "/fmt" for Fmt
import "/fmt" for Fmt


Line 6,800: Line 6,800:
System.print("\nRecovered S-Expression (pretty print):")
System.print("\nRecovered S-Expression (pretty print):")
prettyPrint.call(tokens)
prettyPrint.call(tokens)
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}