181 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Factor
		
	
	
		
			Executable File
		
	
			
		
		
	
	
			181 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Factor
		
	
	
		
			Executable File
		
	
! Copyright (C) 2006 Chris Double.
 | 
						|
! See http://factorcode.org/license.txt for BSD license.
 | 
						|
USING: kernel parser-combinators namespaces make sequences promises strings 
 | 
						|
       assocs math math.parser math.vectors math.functions math.order
 | 
						|
       lists hashtables ascii accessors ;
 | 
						|
IN: json.reader
 | 
						|
 | 
						|
! Grammar for JSON from RFC 4627
 | 
						|
 | 
						|
SYMBOL: json-null
 | 
						|
 | 
						|
: [<&>] ( quot -- quot )
 | 
						|
  { } make unclip [ <&> ] reduce ;
 | 
						|
 | 
						|
: [<|>] ( quot -- quot )
 | 
						|
  { } make unclip [ <|> ] reduce ;
 | 
						|
 | 
						|
LAZY: 'ws' ( -- parser )
 | 
						|
  " " token 
 | 
						|
  "\n" token <|>
 | 
						|
  "\r" token <|>
 | 
						|
  "\t" token <|> <*> ;
 | 
						|
 | 
						|
LAZY: spaced ( parser -- parser )
 | 
						|
  'ws' swap &> 'ws' <& ;
 | 
						|
 | 
						|
LAZY: 'begin-array' ( -- parser )
 | 
						|
  "[" token spaced ;
 | 
						|
 | 
						|
LAZY: 'begin-object' ( -- parser )
 | 
						|
  "{" token spaced ;
 | 
						|
 | 
						|
LAZY: 'end-array' ( -- parser )
 | 
						|
  "]" token spaced ;
 | 
						|
 | 
						|
LAZY: 'end-object' ( -- parser )
 | 
						|
  "}" token spaced ;
 | 
						|
 | 
						|
LAZY: 'name-separator' ( -- parser )
 | 
						|
  ":" token spaced ;
 | 
						|
 | 
						|
LAZY: 'value-separator' ( -- parser )
 | 
						|
  "," token spaced ;
 | 
						|
 | 
						|
LAZY: 'false' ( -- parser )
 | 
						|
  "false" token [ drop f ] <@ ;
 | 
						|
 | 
						|
LAZY: 'null' ( -- parser )
 | 
						|
  "null" token [ drop json-null ] <@ ;
 | 
						|
 | 
						|
LAZY: 'true' ( -- parser )
 | 
						|
  "true" token [ drop t ] <@ ;
 | 
						|
 | 
						|
LAZY: 'quot' ( -- parser )
 | 
						|
  "\"" token ;
 | 
						|
 | 
						|
LAZY: 'hex-digit' ( -- parser )
 | 
						|
  [ digit> ] satisfy [ digit> ] <@ ;
 | 
						|
 | 
						|
: hex-digits>ch ( digits -- ch )
 | 
						|
    0 [ swap 16 * + ] reduce ;
 | 
						|
 | 
						|
LAZY: 'string-char' ( -- parser )
 | 
						|
  [ quotable? ] satisfy
 | 
						|
  "\\b" token [ drop 8 ] <@ <|>
 | 
						|
  "\\t" token [ drop CHAR: \t ] <@ <|>
 | 
						|
  "\\n" token [ drop CHAR: \n ] <@ <|>
 | 
						|
  "\\f" token [ drop 12 ] <@ <|>
 | 
						|
  "\\r" token [ drop CHAR: \r ] <@ <|>
 | 
						|
  "\\\"" token [ drop CHAR: " ] <@ <|>
 | 
						|
  "\\/" token [ drop CHAR: / ] <@ <|>
 | 
						|
  "\\\\" token [ drop CHAR: \\ ] <@ <|>
 | 
						|
  "\\u" token 'hex-digit' 4 exactly-n &>
 | 
						|
  [ hex-digits>ch ] <@ <|> ;
 | 
						|
 | 
						|
LAZY: 'string' ( -- parser )
 | 
						|
  'quot' 
 | 
						|
  'string-char' <*> &> 
 | 
						|
  'quot' <& [ >string ] <@  ;
 | 
						|
 | 
						|
DEFER: 'value'
 | 
						|
 | 
						|
LAZY: 'member' ( -- parser )
 | 
						|
  'string'
 | 
						|
  'name-separator' <&  
 | 
						|
  'value' <&> ;
 | 
						|
 | 
						|
USE: prettyprint 
 | 
						|
LAZY: 'object' ( -- parser )
 | 
						|
  'begin-object' 
 | 
						|
  'member' 'value-separator' list-of &>
 | 
						|
  'end-object' <& [ >hashtable ] <@ ;
 | 
						|
 | 
						|
LAZY: 'array' ( -- parser )
 | 
						|
  'begin-array' 
 | 
						|
  'value' 'value-separator' list-of &>
 | 
						|
  'end-array' <&  ;
 | 
						|
  
 | 
						|
LAZY: 'minus' ( -- parser )
 | 
						|
  "-" token ;
 | 
						|
 | 
						|
LAZY: 'plus' ( -- parser )
 | 
						|
  "+" token ;
 | 
						|
 | 
						|
LAZY: 'sign' ( -- parser )
 | 
						|
  'minus' 'plus' <|> ;
 | 
						|
 | 
						|
LAZY: 'zero' ( -- parser )
 | 
						|
  "0" token [ drop 0 ] <@ ;
 | 
						|
 | 
						|
LAZY: 'decimal-point' ( -- parser )
 | 
						|
  "." token ;
 | 
						|
 | 
						|
LAZY: 'digit1-9' ( -- parser )
 | 
						|
  [ 
 | 
						|
    dup integer? [ 
 | 
						|
      CHAR: 1 CHAR: 9 between? 
 | 
						|
    ] [ 
 | 
						|
      drop f 
 | 
						|
    ] if 
 | 
						|
  ] satisfy [ digit> ] <@ ;
 | 
						|
 | 
						|
LAZY: 'digit0-9' ( -- parser )
 | 
						|
  [ digit? ] satisfy [ digit> ] <@ ;
 | 
						|
 | 
						|
: decimal>integer ( seq -- num ) 10 digits>integer ;
 | 
						|
 | 
						|
LAZY: 'int' ( -- parser )
 | 
						|
  'zero' 
 | 
						|
  'digit1-9' 'digit0-9' <*> <&:> [ decimal>integer ] <@ <|>  ;
 | 
						|
 | 
						|
LAZY: 'e' ( -- parser )
 | 
						|
  "e" token "E" token <|> ;
 | 
						|
 | 
						|
: sign-number ( pair -- number )
 | 
						|
  #! Pair is { minus? num }
 | 
						|
  #! Convert the json number value to a factor number
 | 
						|
  dup second swap first [ first "-" = [ -1 * ] when ] when* ;
 | 
						|
 | 
						|
LAZY: 'exp' ( -- parser )
 | 
						|
    'e' 
 | 
						|
    'sign' <?> &>
 | 
						|
    'digit0-9' <+> [ decimal>integer ] <@ <&> [ sign-number ] <@ ;
 | 
						|
 | 
						|
: sequence>frac ( seq -- num ) 
 | 
						|
  #! { 1 2 3 } => 0.123
 | 
						|
  reverse 0 [ swap 10 / + ] reduce 10 / >float ;
 | 
						|
 | 
						|
LAZY: 'frac' ( -- parser )
 | 
						|
  'decimal-point' 'digit0-9' <+> &> [ sequence>frac ] <@ ;
 | 
						|
 | 
						|
: raise-to-power ( pair -- num )
 | 
						|
  #! Pair is { num exp }.
 | 
						|
  #! Multiply 'num' by 10^exp
 | 
						|
  dup second dup [ 10 swap first ^ swap first * ] [ drop first ] if ;
 | 
						|
 | 
						|
LAZY: 'number' ( -- parser )
 | 
						|
  'sign' <?>
 | 
						|
  [ 'int' , 'frac' 0 succeed <|> , ] [<&>] [ sum ] <@ 
 | 
						|
  'exp' <?> <&> [ raise-to-power ] <@ <&> [ sign-number ] <@ ;
 | 
						|
 | 
						|
LAZY: 'value' ( -- parser )
 | 
						|
  [
 | 
						|
    'false' ,
 | 
						|
    'null' ,
 | 
						|
    'true' ,
 | 
						|
    'string' ,
 | 
						|
    'object' ,
 | 
						|
    'array' ,
 | 
						|
    'number' ,
 | 
						|
  ] [<|>] spaced ;
 | 
						|
ERROR: could-not-parse-json ;
 | 
						|
 | 
						|
: json> ( string -- object )
 | 
						|
  #! Parse a json formatted string to a factor object
 | 
						|
  'value' parse dup nil? [ 
 | 
						|
      could-not-parse-json
 | 
						|
  ] [ 
 | 
						|
    car parsed>> 
 | 
						|
  ] if ;
 |