mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			990 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			ReasonML
		
	
	
	
	
	
			
		
		
	
	
			990 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			ReasonML
		
	
	
	
	
	
/* Copyright (c) 2015-present, Facebook, Inc. All rights reserved. */
 | 
						|
[@@@autoFormat let wrap = 80; let shift = 2];
 | 
						|
 | 
						|
Modules.run ();
 | 
						|
 | 
						|
Polymorphism.run ();
 | 
						|
 | 
						|
Variants.run ();
 | 
						|
 | 
						|
BasicStructures.run ();
 | 
						|
 | 
						|
TestUtils.printSection "General Syntax";
 | 
						|
 | 
						|
/* Won't work! */
 | 
						|
/* let matchingFunc a = match a with */
 | 
						|
/*   `Thingy x => (print_string "matched thingy x"); x */
 | 
						|
/*   | `Other x => (print_string "matched other x"); x;; */
 | 
						|
/*  */
 | 
						|
let matchingFunc a =>
 | 
						|
  switch a {
 | 
						|
  | `Thingy x =>
 | 
						|
    print_string "matched thingy x";
 | 
						|
    let zz = 10;
 | 
						|
    zz
 | 
						|
  | `Other x =>
 | 
						|
    print_string "matched other x";
 | 
						|
    x
 | 
						|
  };
 | 
						|
 | 
						|
type firstTwoShouldBeGroupedInParens =
 | 
						|
  (int => int) => int => int;
 | 
						|
 | 
						|
type allParensCanBeRemoved =
 | 
						|
  int => int => int => int;
 | 
						|
 | 
						|
type firstTwoShouldBeGroupedAndFirstThree =
 | 
						|
  ((int => int) => int) => int;
 | 
						|
 | 
						|
/* Same thing now but with type constructors instead of each int */
 | 
						|
type firstTwoShouldBeGroupedInParens =
 | 
						|
  (list int => list int) => list int => list int;
 | 
						|
 | 
						|
type allParensCanBeRemoved =
 | 
						|
  list int => list int => list int => list int;
 | 
						|
 | 
						|
type firstTwoShouldBeGroupedAndFirstThree =
 | 
						|
  ((list int => list int) => list int) =>
 | 
						|
  list int;
 | 
						|
 | 
						|
type myRecordType = {
 | 
						|
  firstTwoShouldBeGroupedInParens:
 | 
						|
    (int => int) => int => int,
 | 
						|
  allParensCanBeRemoved:
 | 
						|
    int => int => int => int,
 | 
						|
  firstTwoShouldBeGroupedAndFirstThree:
 | 
						|
    ((int => int) => int) => int
 | 
						|
};
 | 
						|
 | 
						|
type firstNamedArgShouldBeGroupedInParens =
 | 
						|
  first::(int => int) => second::int => int;
 | 
						|
 | 
						|
type allParensCanBeRemoved =
 | 
						|
  first::int => second::int => third::int => int;
 | 
						|
 | 
						|
type firstTwoShouldBeGroupedAndFirstThree =
 | 
						|
  first::((int => int) => int) => int;
 | 
						|
 | 
						|
/* Same thing now, but with type constructors instead of int */
 | 
						|
type firstNamedArgShouldBeGroupedInParens =
 | 
						|
  first::(list int => list int) =>
 | 
						|
  second::list int =>
 | 
						|
  list int;
 | 
						|
 | 
						|
type allParensCanBeRemoved =
 | 
						|
  first::list int =>
 | 
						|
  second::list int =>
 | 
						|
  third::list int =>
 | 
						|
  list int;
 | 
						|
 | 
						|
type firstTwoShouldBeGroupedAndFirstThree =
 | 
						|
  first::((list int => list int) => list int) =>
 | 
						|
  list int;
 | 
						|
 | 
						|
type firstNamedArgShouldBeGroupedInParens =
 | 
						|
  first::(int => int)? =>
 | 
						|
  second::int list? =>
 | 
						|
  int;
 | 
						|
 | 
						|
/* The arrow necessitates parens around the next two args. The ? isn't what
 | 
						|
 * makes the parens necessary. */
 | 
						|
type firstNamedArgShouldBeGroupedInParensAndSecondNamedArg =
 | 
						|
  first::(int => int)? =>
 | 
						|
  second::(int => int)? =>
 | 
						|
  int;
 | 
						|
 | 
						|
type allParensCanBeRemoved =
 | 
						|
  first::int? =>
 | 
						|
  second::int? =>
 | 
						|
  third::int? =>
 | 
						|
  int;
 | 
						|
 | 
						|
type firstTwoShouldBeGroupedAndFirstThree =
 | 
						|
  first::((int => int) => int) => int;
 | 
						|
 | 
						|
type noParens =
 | 
						|
  one::int => int => int => two::int => int;
 | 
						|
 | 
						|
type noParensNeeded =
 | 
						|
  one::int => int => int => two::int => int;
 | 
						|
 | 
						|
type firstNamedArgNeedsParens =
 | 
						|
  one::(int => int => int) => two::int => int;
 | 
						|
 | 
						|
/* Now, let's try type aliasing */
 | 
						|
/* Unless wrapped in parens, types between arrows may not be aliased, may not
 | 
						|
 * themselves be arrows. */
 | 
						|
type parensRequiredAroundFirstArg =
 | 
						|
  (list int as 'a) => int as 'a;
 | 
						|
 | 
						|
type parensRequiredAroundReturnType =
 | 
						|
  (list int as 'a) => (int as 'a);
 | 
						|
 | 
						|
type parensRequiredAroundReturnType =
 | 
						|
  (list int as 'a) => (int as 'a) as 'b;
 | 
						|
 | 
						|
type noParensNeededWhenInTuple =
 | 
						|
  (list int as 'a, list int as 'b) as 'entireThing;
 | 
						|
 | 
						|
type myTypeDef 'a = list 'a;
 | 
						|
 | 
						|
type instatiatedTypeDef = myTypeDef int => int;
 | 
						|
 | 
						|
/* Test a type attribute for good measure */
 | 
						|
/* We should clean up all of the attribute tagging eventually, but for now,
 | 
						|
 * let's make it super ugly to get out of the way of all the formatting/parsing
 | 
						|
 * implementations (fewer conflicts during parsing, fewer edge cases during
 | 
						|
 * printing).
 | 
						|
 */
 | 
						|
type something = (
 | 
						|
  int,
 | 
						|
  int [@lookAtThisAttribute]
 | 
						|
);
 | 
						|
 | 
						|
type longWrappingTypeDefinitionExample =
 | 
						|
  M_RK__G.Types.instance
 | 
						|
    (TGRecognizer.tGFields unit unit)
 | 
						|
    (TGRecognizer.tGMethods unit unit);
 | 
						|
 | 
						|
type semiLongWrappingTypeDefinitionExample =
 | 
						|
  M_RK__Gesture.Types.instance
 | 
						|
    TGRecognizerFinal.tGFields
 | 
						|
    TGRecognizerFinal.tGMethods;
 | 
						|
 | 
						|
type semiLongWrappingTypeWithConstraint =
 | 
						|
  M_RK__Gesture.Types.instance
 | 
						|
    'a
 | 
						|
    TGRecognizerFinal.tGFields
 | 
						|
    TGRecognizerFinal.tGMethods
 | 
						|
constraint 'a = (unit, unit);
 | 
						|
 | 
						|
type onelineConstrain = 'a constraint 'a = int;
 | 
						|
 | 
						|
/* This must be in trunk but not in this branch of OCaml */
 | 
						|
/* type withNestedRecords = MyConstructor {myField: int} */
 | 
						|
type colors =
 | 
						|
  | Red int
 | 
						|
  | Black int
 | 
						|
  | Green int;
 | 
						|
 | 
						|
/* Another approach is to require declared variants to wrap any record */
 | 
						|
/* type myRecord = MyRecord {name: int}; */
 | 
						|
/* let myValue = MyRecord {name: int}; */
 | 
						|
/* This would force importing of the module */
 | 
						|
/* This would also lend itself naturally to pattern matching - and avoid having
 | 
						|
   to use `.` operator at all since you normally destructure. */
 | 
						|
type nameBlahType = {nameBlah: int};
 | 
						|
 | 
						|
let myRecord = {nameBlah: 20};
 | 
						|
 | 
						|
let myRecordName = myRecord.nameBlah;
 | 
						|
 | 
						|
let {nameBlah}: nameBlahType = {nameBlah: 20};
 | 
						|
 | 
						|
print_int nameBlah;
 | 
						|
 | 
						|
let {nameBlah: aliasedToThisVar}: nameBlahType = {
 | 
						|
  nameBlah: 20
 | 
						|
};
 | 
						|
 | 
						|
print_int aliasedToThisVar;
 | 
						|
 | 
						|
let desiredFormattingForWrappedLambda:
 | 
						|
  int => int => int => nameBlahType =
 | 
						|
  /*
 | 
						|
 | 
						|
   fun is
 | 
						|
   pre-   /firstarg\
 | 
						|
   fix   /-coupled--\
 | 
						|
    |-\ /-to-prefix--\       */
 | 
						|
  fun curriedArg anotherArg lastArg => {
 | 
						|
    nameBlah: 10
 | 
						|
  };
 | 
						|
 | 
						|
type longerInt = int;
 | 
						|
 | 
						|
let desiredFormattingForWrappedLambdaWrappedArrow:
 | 
						|
  longerInt =>
 | 
						|
  longerInt =>
 | 
						|
  longerInt =>
 | 
						|
  nameBlahType =
 | 
						|
  /*
 | 
						|
 | 
						|
   fun is
 | 
						|
   pre-   /firstarg\
 | 
						|
   fix   /-coupled--\
 | 
						|
    |-\ /-to-prefix--\       */
 | 
						|
  fun curriedArg anotherArg lastArg => {
 | 
						|
    nameBlah: 10
 | 
						|
  };
 | 
						|
 | 
						|
let desiredFormattingForWrappedLambdaReturnOnNewLine
 | 
						|
    /*
 | 
						|
 | 
						|
     fun is
 | 
						|
     pre-   /firstarg\
 | 
						|
     fix   /-coupled--\
 | 
						|
      |-\ /-to-prefix--\       */
 | 
						|
    curriedArg
 | 
						|
    anotherArg
 | 
						|
    lastArg => {
 | 
						|
  nameBlah: 10
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
 let is
 | 
						|
 pre-
 | 
						|
 fix    /-function binding name---\
 | 
						|
 |-\   / is coupled to prefix      \   */
 | 
						|
let desiredFormattingForWrappedSugar
 | 
						|
    curriedArg
 | 
						|
    anotherArg
 | 
						|
    lastArg => {
 | 
						|
  nameBlah: 10
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
 let is
 | 
						|
 pre-
 | 
						|
 fix    /-function binding name---\
 | 
						|
 |-\   / is coupled to prefix      \   */
 | 
						|
let desiredFormattingForWrappedSugarReturnOnNewLine
 | 
						|
    curriedArg
 | 
						|
    anotherArg
 | 
						|
    lastArg => {
 | 
						|
  nameBlah: 10
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
   let  : type t1 t2. t1 * t2 list -> t1 = ...
 | 
						|
   let rec f : 't1 't2. 't1 * 't2 list -> 't1 =
 | 
						|
     fun (type t1) (type t2) -> (... : t1 * t2 list -> t1)
 | 
						|
 */
 | 
						|
type point = {x: int, y: int};
 | 
						|
 | 
						|
type point3D = {x: int, y: int, z: int};
 | 
						|
 | 
						|
let point2D = {x: 20, y: 30};
 | 
						|
 | 
						|
let point3D: point3D = {
 | 
						|
  x: 10,
 | 
						|
  y: 11,
 | 
						|
  z: 80 /* Optional Comma */
 | 
						|
};
 | 
						|
 | 
						|
let printPoint (p: point) => {
 | 
						|
  print_int p.x;
 | 
						|
  print_int p.y
 | 
						|
};
 | 
						|
 | 
						|
let addPoints (p1: point, p2: point) => {
 | 
						|
  x: p1.x + p2.x,
 | 
						|
  y: p1.y + p2.y
 | 
						|
};
 | 
						|
 | 
						|
let res1 = printPoint point2D;
 | 
						|
 | 
						|
let res2 =
 | 
						|
  printPoint {x: point3D.x, y: point3D.y};
 | 
						|
 | 
						|
/*
 | 
						|
    When () were used to indicate sequences, the parser used seq_expr not only
 | 
						|
    for grouping sequences, but also to form standard precedences.
 | 
						|
                          /------- sequence_expr ------\
 | 
						|
    let res3 = printPoint (addPoints (point2D, point3D));
 | 
						|
 | 
						|
    Interestingly, it knew that tuples aren't sequences.
 | 
						|
 | 
						|
    To move towards semi delimited, semi-terminated, braces-grouped sequences:
 | 
						|
    while allowing any non-sequence expression to be grouped on parens, we make
 | 
						|
    an explicit rule that allows one single non-semi ended expression to be
 | 
						|
    grouped in parens.
 | 
						|
 | 
						|
    Actually: We will allow an arbitrary number of semi-delimited expressions to
 | 
						|
    be wrapped in parens, but the braces grouped semi delimited (sequence)
 | 
						|
    expressions must *also* be terminated with a semicolon.
 | 
						|
 | 
						|
    This allows the parser to distinguish between
 | 
						|
 | 
						|
        let x = {a};    /* Record {a:a} */
 | 
						|
        let x = {a;};   /* Single item sequence returning identifier {a} */
 | 
						|
 */
 | 
						|
let res3 =
 | 
						|
  printPoint (
 | 
						|
    addPoints (
 | 
						|
      point2D,
 | 
						|
      {x: point3D.x, y: point3D.y}
 | 
						|
    )
 | 
						|
  );
 | 
						|
 | 
						|
type person = {age: int, name: string};
 | 
						|
 | 
						|
type hiredPerson = {
 | 
						|
  age: string,
 | 
						|
  name: string,
 | 
						|
  dateHired: int
 | 
						|
};
 | 
						|
 | 
						|
let o: person = {name: "bob", age: 10};
 | 
						|
 | 
						|
/* Parens needed? Nope! */
 | 
						|
let o: person = {name: "bob", age: 10};
 | 
						|
 | 
						|
let printPerson (p: person) => {
 | 
						|
  let q: person = p;
 | 
						|
  p.name ^ p.name
 | 
						|
};
 | 
						|
 | 
						|
/* let dontParseMeBro x y:int = x = y;*/
 | 
						|
/* With this unification, anywhere eyou see `= fun` you can just ommit it */
 | 
						|
let blah a => a; /* Done */
 | 
						|
 | 
						|
let blah a => a; /* Done (almost) */
 | 
						|
 | 
						|
let blah a b => a; /* Done */
 | 
						|
 | 
						|
let blah a b => a; /* Done (almost) */
 | 
						|
 | 
						|
/* More than one consecutive pattern must have a single case */
 | 
						|
type blah = {blahBlah: int};
 | 
						|
 | 
						|
let blah a {blahBlah} => a;
 | 
						|
 | 
						|
let blah a {blahBlah} => a;
 | 
						|
 | 
						|
let module TryToExportTwice = {
 | 
						|
  let myVal = "hello";
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
   Unifying top level module syntax with local module syntax is probably a bad
 | 
						|
   idea at the moment because it makes it more difficult to continue to support
 | 
						|
   `let .. in` bindings. We can distinguish local modules for `let..in` that
 | 
						|
   just happen to be defined at the top level (but not exported).
 | 
						|
 | 
						|
     let MyModule = {let myVal = 20;} in
 | 
						|
     MyModule.x
 | 
						|
 | 
						|
   Wait, where would this ever be valid, even if we continued to support
 | 
						|
   `let..in`?
 | 
						|
 */
 | 
						|
let onlyDoingThisTopLevelLetToBypassTopLevelSequence = {
 | 
						|
  let x = {
 | 
						|
    print_int 1;
 | 
						|
    print_int 20 /* Missing trailing SEMI */
 | 
						|
  };
 | 
						|
  let x = {
 | 
						|
    print_int 1;
 | 
						|
    print_int 20; /* Ensure missing middle SEMI reported well */
 | 
						|
    print_int 20
 | 
						|
  };
 | 
						|
  let x = {
 | 
						|
    print_int 1;
 | 
						|
    print_int 20;
 | 
						|
    10
 | 
						|
    /* Comment in final position */
 | 
						|
  }; /* Missing final SEMI */
 | 
						|
  x + x
 | 
						|
};
 | 
						|
 | 
						|
type hasA = {a: int};
 | 
						|
 | 
						|
let a = 10;
 | 
						|
 | 
						|
let returnsASequenceExpressionWithASingleIdentifier
 | 
						|
    () => a;
 | 
						|
 | 
						|
let thisReturnsA () => a;
 | 
						|
 | 
						|
let thisReturnsAAsWell () => a;
 | 
						|
 | 
						|
let recordVal: int = (thisReturnsARecord ()).a;
 | 
						|
 | 
						|
Printf.printf
 | 
						|
  "\nproof that thisReturnsARecord: %n\n"
 | 
						|
  recordVal;
 | 
						|
 | 
						|
Printf.printf
 | 
						|
  "\nproof that thisReturnsA: %n\n"
 | 
						|
  (thisReturnsA ());
 | 
						|
 | 
						|
/* Pattern matching */
 | 
						|
let blah arg =>
 | 
						|
  switch arg {
 | 
						|
  /* Comment before Bar */
 | 
						|
  | /* Comment between bar/pattern */ Red _ => 1
 | 
						|
  /* Comment Before non-first bar */
 | 
						|
  | /* Comment betwen bar/pattern */ Black _ => 0
 | 
						|
  | Green _ => 0
 | 
						|
  };
 | 
						|
 | 
						|
/* Any function that pattern matches a multicase match is interpretted as a
 | 
						|
 * single arg that is then matched on. Instead of the above `blah` example:*/
 | 
						|
let blah =
 | 
						|
  fun
 | 
						|
  | Red _ => 1
 | 
						|
  | Black _ => 0
 | 
						|
  | Green _ => 1;
 | 
						|
 | 
						|
/* `fun a => a` is read as "a function that maps a to a". Then the */
 | 
						|
/* above example is read: "a function that 'either maps' Red to.. or maps .." */
 | 
						|
/* Thc00f564e first bar is read as "either maps" */
 | 
						|
/* Curried form is not supported:
 | 
						|
      let blah x | Red _ => 1 | Black _ => 0;
 | 
						|
      Theres no sugar rule for dropping => fun, only = fun
 | 
						|
   */
 | 
						|
/* let blahCurriedX x => fun  /* See, nothing says we can drop the => fun */ */
 | 
						|
/*   |(Red x | Black x | Green x) => 1     /* With some effort, we can ammend the sugar rule that would */ */
 | 
						|
/*   | Black x => 0                       /* Allow us to drop any => fun.. Just need to make pattern matching */ */
 | 
						|
/*   | Green x => 0;                      /* Support that */ */
 | 
						|
/*  */
 | 
						|
let blahCurriedX x =>
 | 
						|
  fun
 | 
						|
  | Red x
 | 
						|
  | Black x
 | 
						|
  | Green x =>
 | 
						|
    1 /* With some effort, we can ammend the sugar rule that would */
 | 
						|
  | Black x => 0 /* Allow us to drop any => fun.. Just need to make pattern matching */
 | 
						|
  | Green x => 0; /* Support that */
 | 
						|
 | 
						|
let sameThingInLocal = {
 | 
						|
  let blahCurriedX x =>
 | 
						|
    fun
 | 
						|
    | Red x
 | 
						|
    | Black x
 | 
						|
    | Green x =>
 | 
						|
      1 /* With some effort, we can ammend the sugar rule that would */
 | 
						|
    | Black x => 0 /* Allow us to drop any => fun.. Just need to make pattern matching */
 | 
						|
    | Green x => 0; /* Support that */
 | 
						|
  blahCurriedX
 | 
						|
};
 | 
						|
 | 
						|
/* This should be parsed/printed exactly as the previous */
 | 
						|
let blahCurriedX x =>
 | 
						|
  fun
 | 
						|
  | Red x
 | 
						|
  | Black x
 | 
						|
  | Green x => 1
 | 
						|
  | Black x => 0
 | 
						|
  | Green x => 0;
 | 
						|
 | 
						|
/* Any time there are multiple match cases we require a leading BAR */
 | 
						|
let v = Red 10;
 | 
						|
 | 
						|
let Black x | Red x | Green x = v; /* So this NON-function still parses */
 | 
						|
 | 
						|
/* This doesn't parse, however (and it doesn't in OCaml either):
 | 
						|
     let | Black x | Red x | Green x = v;
 | 
						|
   */
 | 
						|
print_int x;
 | 
						|
 | 
						|
/* Scoping: Let sequences. Familiar syntax for lexical ML style scope and
 | 
						|
   sequences. */
 | 
						|
let res = {
 | 
						|
  let a = "a starts out as";
 | 
						|
  {
 | 
						|
    print_string a;
 | 
						|
    let a = 20;
 | 
						|
    print_int a
 | 
						|
  };
 | 
						|
  print_string a
 | 
						|
};
 | 
						|
 | 
						|
let res = {
 | 
						|
  let a = "first its a string";
 | 
						|
  let a = 20;
 | 
						|
  print_int a;
 | 
						|
  print_int a;
 | 
						|
  print_int a
 | 
						|
};
 | 
						|
 | 
						|
let res = {
 | 
						|
  let a = "a is always a string";
 | 
						|
  print_string a;
 | 
						|
  let b = 30;
 | 
						|
  print_int b
 | 
						|
};
 | 
						|
 | 
						|
/* let result = LyList.map (fun | [] => true | _ => false) []; */
 | 
						|
/* OTHERWISE: You cannot tell if a is the first match case falling through or
 | 
						|
 * a curried first arg */
 | 
						|
/* let blah = fun a | patt => 0 | anotherPatt => 1; */
 | 
						|
/* let blah a patt => 0 | anotherPatt => 1; */
 | 
						|
/*simple pattern  EQUALGREATER      expr */
 | 
						|
let blah a {blahBlah} => a;
 | 
						|
 | 
						|
/*            match_case             */
 | 
						|
/*     pattern EQUALGREATER  expr */
 | 
						|
let blah =
 | 
						|
  fun
 | 
						|
  | Red _ => 1
 | 
						|
  | Black _ => 0
 | 
						|
  | Green _ => 0;
 | 
						|
 | 
						|
/* Won't work! */
 | 
						|
/* let arrowFunc = fun a b => print_string "returning aplusb from arrow"; a + b;;  */
 | 
						|
let arrowFunc a b => {
 | 
						|
  print_string "returning aplusb from arrow";
 | 
						|
  a + b
 | 
						|
};
 | 
						|
 | 
						|
let add a b => {
 | 
						|
  let extra = {
 | 
						|
    print_string "adding";
 | 
						|
    0
 | 
						|
  };
 | 
						|
  let anotherExtra = 0;
 | 
						|
  extra + a + b + anotherExtra
 | 
						|
};
 | 
						|
 | 
						|
print_string (string_of_int (add 4 34));
 | 
						|
 | 
						|
let dummy _ => 10;
 | 
						|
 | 
						|
dummy res1;
 | 
						|
 | 
						|
dummy res2;
 | 
						|
 | 
						|
dummy res3;
 | 
						|
 | 
						|
/* Some edge cases */
 | 
						|
let myFun firstArg (Red x | Black x | Green x) =>
 | 
						|
  firstArg + x;
 | 
						|
 | 
						|
let matchesWithWhen a =>
 | 
						|
  switch a {
 | 
						|
  | Red x when 1 > 0 => 10
 | 
						|
  | Red _ => 10
 | 
						|
  | Black x => 10
 | 
						|
  | Green x => 10
 | 
						|
  };
 | 
						|
 | 
						|
let matchesWithWhen =
 | 
						|
  fun
 | 
						|
  | Red x when 1 > 0 => 10
 | 
						|
  | Red _ => 10
 | 
						|
  | Black x => 10
 | 
						|
  | Green x => 10;
 | 
						|
 | 
						|
let matchesOne (`Red x) => 10;
 | 
						|
 | 
						|
/*
 | 
						|
 Typical OCaml would make you *wrap the functions in parens*! This is because it
 | 
						|
 can't tell if a semicolon is a sequence operator. Even if we had records use
 | 
						|
 commas to separate fields,
 | 
						|
 */
 | 
						|
type adders = {
 | 
						|
  addTwoNumbers: int => int => int,
 | 
						|
  addThreeNumbers: int => int => int => int,
 | 
						|
  addThreeNumbersTupled: (int, int, int) => int
 | 
						|
};
 | 
						|
 | 
						|
let myRecordWithFunctions = {
 | 
						|
  addTwoNumbers: fun a b => a + b,
 | 
						|
  addThreeNumbers: fun a b c => a + b + c,
 | 
						|
  addThreeNumbersTupled: fun (a, b, c) =>
 | 
						|
    a + b + c
 | 
						|
};
 | 
						|
 | 
						|
let result =
 | 
						|
  myRecordWithFunctions.addThreeNumbers 10 20 30;
 | 
						|
 | 
						|
let result =
 | 
						|
  myRecordWithFunctions.addThreeNumbersTupled (
 | 
						|
    10,
 | 
						|
    20,
 | 
						|
    30
 | 
						|
  );
 | 
						|
 | 
						|
let lookTuplesRequireParens = (1, 2);
 | 
						|
 | 
						|
/* let thisDoesntParse = 1, 2;  */
 | 
						|
let tupleInsideAParenSequence = {
 | 
						|
  print_string "look, a tuple inside a sequence";
 | 
						|
  let x = 10;
 | 
						|
  (x, x)
 | 
						|
};
 | 
						|
 | 
						|
let tupleInsideALetSequence = {
 | 
						|
  print_string "look, a tuple inside a sequence";
 | 
						|
  let x = 10;
 | 
						|
  (x, x)
 | 
						|
};
 | 
						|
 | 
						|
/* We *require* that function return types be wrapped in
 | 
						|
   parenthesis. In this example, there's no ambiguity */
 | 
						|
let makeIncrementer (delta: int) :(int => int) =>
 | 
						|
  fun a => a + delta;
 | 
						|
 | 
						|
/* We could even force that consistency with let bindings - it's allowed
 | 
						|
      currently but not forced.
 | 
						|
   */
 | 
						|
let myAnnotatedValBinding: int = 10;
 | 
						|
 | 
						|
/* Class functions (constructors) and methods are unified in the same way */
 | 
						|
class classWithNoArg = {
 | 
						|
  method x = 0;
 | 
						|
  method y = 0;
 | 
						|
};
 | 
						|
 | 
						|
/* This parses but doesn't type check
 | 
						|
     class myClass init => object
 | 
						|
       method x => init
 | 
						|
       method y => init
 | 
						|
     end;
 | 
						|
   */
 | 
						|
let myFunc (a: int) (b: int) :(int, int) => (
 | 
						|
  a,
 | 
						|
  b
 | 
						|
);
 | 
						|
 | 
						|
let myFunc (a: int) (b: int) :list int => [1];
 | 
						|
 | 
						|
let myFunc (a: int) (b: int) :point => {
 | 
						|
  x: a,
 | 
						|
  y: b
 | 
						|
};
 | 
						|
 | 
						|
let myFunc (a: int, b: int) :point => {
 | 
						|
  x: a,
 | 
						|
  y: b
 | 
						|
};
 | 
						|
 | 
						|
type myThing = (int, int);
 | 
						|
 | 
						|
type stillARecord = {name: string, age: int};
 | 
						|
 | 
						|
/* Rebase latest OCaml to get the following: And fixup
 | 
						|
   `generalized_constructor_arguments` according to master. */
 | 
						|
/* type ('a, 'b) myOtherThing = Leaf {first:'a, second: 'b} | Null; */
 | 
						|
type branch 'a 'b = {first: 'a, second: 'b};
 | 
						|
 | 
						|
type myOtherThing 'a 'b =
 | 
						|
  | Leaf (branch 'a 'b)
 | 
						|
  | Null;
 | 
						|
 | 
						|
type yourThing = myOtherThing int int;
 | 
						|
 | 
						|
/* Conveniently - this parses exactly how you would intend! No *need* to wrap
 | 
						|
   in an extra [], but it doesn't hurt */
 | 
						|
/* FIXME type lookAtThesePolyVariants = list [`Red] ; */
 | 
						|
/* FIXME type bracketsGroupMultipleParamsAndPrecedence = list (list (list [`Red])); */
 | 
						|
/* FIXME type youCanWrapExtraIfYouWant = (list [`Red]); */
 | 
						|
/* FIXME type hereAreMultiplePolyVariants = list [`Red | `Black]; */
 | 
						|
/* FIXME type hereAreMultiplePolyVariantsWithOptionalWrapping = list ([`Red | `Black]); */
 | 
						|
/*
 | 
						|
   /* Proposal: ES6 style lambdas: */
 | 
						|
 | 
						|
   /* Currying */
 | 
						|
   let lookES6Style = (`Red x) (`Black y) => { };
 | 
						|
   let lookES6Style (`Red x) (`Black y) => { };
 | 
						|
 | 
						|
   /* Matching the single argument */
 | 
						|
   let lookES6Style = oneArg => match oneArg with
 | 
						|
     | `Red x => x
 | 
						|
     | `Black x => x;
 | 
						|
 | 
						|
   /* The "trick" to currying that we already have is basically the same - we just
 | 
						|
    * have to reword it a bit:
 | 
						|
    * From:
 | 
						|
    * "Any time you see [let x = fun ...] just replace it with [let x ...]"
 | 
						|
    * To:
 | 
						|
    * "Any time you see [let x = ... => ] just replace it with [let x ... => ]"
 | 
						|
    */
 | 
						|
   let lookES6Style oneArg => match oneArg with
 | 
						|
     | `Red x => x
 | 
						|
     | `Black x => x;
 | 
						|
 | 
						|
 */
 | 
						|
 | 
						|
/** Current OCaml Named Arguments. Any aliasing is more than just aliasing!
 | 
						|
    OCaml allows full on pattern matching of named args. */
 | 
						|
/*
 | 
						|
 A: let named              ~a    ~b                = aa + bb in
 | 
						|
 B: let namedAlias         ~a:aa ~b:bb             = aa + bb in
 | 
						|
 C: let namedAnnot         ~(a:int) ~(b:int)       = a + b in
 | 
						|
 D: let namedAliasAnnot    ~a:(aa:int) ~b:(bb:int) = aa + bb in
 | 
						|
 E: let optional           ?a    ?b                              = 10 in
 | 
						|
 F: let optionalAlias      ?a:aa ?b:bb                           = 10 in
 | 
						|
 G: let optionalAnnot      ?(a:int option) ?(b:int option)       = 10 in
 | 
						|
 H: let optionalAliasAnnot ?a:(aa:int option) ?b:(bb:int option) = 10 in
 | 
						|
 /*
 | 
						|
 Look! When a default is provided, annotation causes inferred type of argument
 | 
						|
 to not be "option" since it's automatically destructured (because we know it
 | 
						|
 will always be available one way or another.)
 | 
						|
 */
 | 
						|
 I: let defOptional           ?(a=10)    ?(b=10)                 = 10 in
 | 
						|
 J: let defOptionalAlias      ?a:(aa=10) ?b:(bb=10)              = 10 in
 | 
						|
 K: let defOptionalAnnot      ?(a:int=10) ?(b:int=10)            = 10 in
 | 
						|
                             \       \
 | 
						|
                              \label_let_pattern opt_default: no longer needed in SugarML
 | 
						|
 | 
						|
 L: let defOptionalAliasAnnot ?a:(aa:int=10) ?b:(bb:int=10)      = 10 in
 | 
						|
                               \        \
 | 
						|
                                \let_pattern: still a useful syntactic building block in SugarML
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * In Reason, the syntax for named args uses double semicolon, since
 | 
						|
 * the syntax for lists uses ES6 style [], freeing up the ::.
 | 
						|
 */
 | 
						|
let a = 10;
 | 
						|
 | 
						|
let b = 20;
 | 
						|
 | 
						|
/*A*/
 | 
						|
let named a::a b::b => a + b;
 | 
						|
 | 
						|
type named = a::int => b::int => int;
 | 
						|
 | 
						|
/*B*/
 | 
						|
let namedAlias a::aa b::bb => aa + bb;
 | 
						|
 | 
						|
let namedAlias a::aa b::bb => aa + bb;
 | 
						|
 | 
						|
type namedAlias = a::int => b::int => int;
 | 
						|
 | 
						|
/*C*/
 | 
						|
let namedAnnot a::(a: int) b::(b: int) => 20;
 | 
						|
 | 
						|
/*D*/
 | 
						|
let namedAliasAnnot a::(aa: int) b::(bb: int) => 20;
 | 
						|
 | 
						|
/*E*/
 | 
						|
let myOptional a::a=? b::b=? () => 10;
 | 
						|
 | 
						|
type named = a::int? => b::int? => unit => int;
 | 
						|
 | 
						|
/*F*/
 | 
						|
let optionalAlias a::aa=? b::bb=? () => 10;
 | 
						|
 | 
						|
/*G*/
 | 
						|
let optionalAnnot a::(a: int)=? b::(b: int)=? () => 10;
 | 
						|
 | 
						|
/*H*/
 | 
						|
let optionalAliasAnnot
 | 
						|
    a::(aa: int)=?
 | 
						|
    b::(bb: int)=?
 | 
						|
    () => 10;
 | 
						|
 | 
						|
/*I: */
 | 
						|
let defOptional a::a=10 b::b=10 () => 10;
 | 
						|
 | 
						|
type named = a::int? => b::int? => unit => int;
 | 
						|
 | 
						|
/*J*/
 | 
						|
let defOptionalAlias a::aa=10 b::bb=10 () => 10;
 | 
						|
 | 
						|
/*K*/
 | 
						|
let defOptionalAnnot
 | 
						|
    a::(a: int)=10
 | 
						|
    b::(b: int)=10
 | 
						|
    () => 10;
 | 
						|
 | 
						|
/*L*/
 | 
						|
let defOptionalAliasAnnot
 | 
						|
    a::(aa: int)=10
 | 
						|
    b::(bb: int)=10
 | 
						|
    () => 10;
 | 
						|
 | 
						|
/*M: Invoking them - Punned */
 | 
						|
let resNotAnnotated = named a::a b::b;
 | 
						|
 | 
						|
/*N:*/
 | 
						|
let resAnnotated: int = named a::a b::b;
 | 
						|
 | 
						|
/*O: Invoking them */
 | 
						|
let resNotAnnotated = named a::a b::b;
 | 
						|
 | 
						|
/*P: Invoking them */
 | 
						|
let resAnnotated: int = named a::a b::b;
 | 
						|
 | 
						|
/*Q: Here's why "punning" doesn't work!  */
 | 
						|
/* Is b:: punned with a final non-named arg, or is b:: supplied b as one named arg? */
 | 
						|
let b = 20;
 | 
						|
 | 
						|
let resAnnotated = named a::a b::b;
 | 
						|
 | 
						|
/*R: Proof that there are no ambiguities with return values being annotated */
 | 
						|
let resAnnotated: ty = named a::a b;
 | 
						|
 | 
						|
/*S: Explicitly passed optionals are a nice way to say "use the default value"*/
 | 
						|
let explictlyPassed =
 | 
						|
  myOptional a::?None b::?None;
 | 
						|
 | 
						|
/*T: Annotating the return value of the entire function call */
 | 
						|
let explictlyPassedAnnotated: int =
 | 
						|
  myOptional a::?None b::?None;
 | 
						|
 | 
						|
/*U: Explicitly passing optional with identifier expression */
 | 
						|
let a = None;
 | 
						|
 | 
						|
let explictlyPassed = myOptional a::?a b::?None;
 | 
						|
 | 
						|
let explictlyPassedAnnotated: int =
 | 
						|
  myOptional a::?a b::?None;
 | 
						|
 | 
						|
let nestedLet = {
 | 
						|
  let _ = 1;
 | 
						|
  ()
 | 
						|
};
 | 
						|
 | 
						|
let nestedLet = {
 | 
						|
  let _ = 1;
 | 
						|
  ()
 | 
						|
};
 | 
						|
 | 
						|
let nestedLet = {
 | 
						|
  let _ = 1;
 | 
						|
  ()
 | 
						|
};
 | 
						|
 | 
						|
let nestedLet = {
 | 
						|
  let _ = 1;
 | 
						|
  2
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
 * Showing many combinations of type annotations and named arguments.
 | 
						|
 */
 | 
						|
type typeWithNestedNamedArgs =
 | 
						|
  outerOne::(
 | 
						|
    innerOne::int => innerTwo::int => int
 | 
						|
  ) =>
 | 
						|
  outerTwo::int =>
 | 
						|
  int;
 | 
						|
 | 
						|
type typeWithNestedOptionalNamedArgs =
 | 
						|
  outerOne::
 | 
						|
    (innerOne::int => innerTwo::int => int)? =>
 | 
						|
  outerTwo::int? =>
 | 
						|
  int;
 | 
						|
 | 
						|
type typeWithNestedOptionalNamedArgs =
 | 
						|
  outerOne::list string? => outerTwo::int? => int;
 | 
						|
 | 
						|
let x =
 | 
						|
  callSomeFunction
 | 
						|
    withArg::10 andOtherArg::wrappedArg;
 | 
						|
 | 
						|
let res = {
 | 
						|
  (constraintedSequenceItem: string);
 | 
						|
  (dontKnowWheYoudWantToActuallyDoThis: string)
 | 
						|
};
 | 
						|
 | 
						|
let res = {
 | 
						|
  (
 | 
						|
    butTheyWillBePrintedWithAppropriateSpacing: string
 | 
						|
  );
 | 
						|
  (soAsToInstillBestDevelopmentPractices: string)
 | 
						|
};
 | 
						|
 | 
						|
let x = [
 | 
						|
  (eachItemInListCanBeAnnotated: int),
 | 
						|
  (typeConstraints: float),
 | 
						|
  (
 | 
						|
    tupleConstraints: int,
 | 
						|
    andNotFunctionInvocations: int
 | 
						|
  )
 | 
						|
];
 | 
						|
 | 
						|
let x = [
 | 
						|
  (butWeWillPrint: int),
 | 
						|
  (themAsSpaceSeparated: float),
 | 
						|
  (toInfluenceYour: int, developmentHabbits: int)
 | 
						|
];
 | 
						|
 | 
						|
let newRecord = {
 | 
						|
  ...(annotatedSpreadRecord: someRec),
 | 
						|
  x: y
 | 
						|
};
 | 
						|
 | 
						|
let newRecord = {
 | 
						|
  ...(annotatedSpreadRecord: someRec),
 | 
						|
  blah: 0,
 | 
						|
  foo: 1
 | 
						|
};
 | 
						|
 | 
						|
let newRecord = {
 | 
						|
  ...(
 | 
						|
    youCanEvenCallMethodsHereAndAnnotate them: someRec
 | 
						|
  ),
 | 
						|
  blah: 0,
 | 
						|
  foo: 1
 | 
						|
};
 | 
						|
 | 
						|
let newRecord = {
 | 
						|
  ...(
 | 
						|
    youCanEvenCallMethodsHereAndAnnotate
 | 
						|
      them named::10: someRec
 | 
						|
  ),
 | 
						|
  blah: 0,
 | 
						|
  foo: 1
 | 
						|
};
 | 
						|
 | 
						|
let something: thing blah = aTypeAnnotation;
 | 
						|
 | 
						|
let something: thing blah = thisIsANamedArg;
 | 
						|
 | 
						|
let something: thing blah = aTypeAnnotation;
 | 
						|
 | 
						|
let something: blah = thisIsANamedArg thing;
 | 
						|
 | 
						|
let something: blah = typeAnnotation thing;
 | 
						|
 | 
						|
let newRecord = {
 | 
						|
  ...(
 | 
						|
    heresAFunctionWithNamedArgs argOne::i: annotatedResult
 | 
						|
  ),
 | 
						|
  soAsToInstill: 0,
 | 
						|
  developmentHabbits: 1
 | 
						|
};
 | 
						|
 | 
						|
[@@@thisIsAThing];
 | 
						|
 | 
						|
let x = 10;
 | 
						|
 | 
						|
/* Ensure that the parenthesis are preserved here because they are
 | 
						|
 * important:
 | 
						|
 */
 | 
						|
let something =
 | 
						|
  fun
 | 
						|
  | None => (
 | 
						|
      fun
 | 
						|
      | [] => "emptyList"
 | 
						|
      | [_, ..._] => "nonEmptyList"
 | 
						|
    )
 | 
						|
  | Some _ => (
 | 
						|
      fun
 | 
						|
      | [] => "emptyList"
 | 
						|
      | [_, ..._] => "nonEmptyList"
 | 
						|
    );
 | 
						|
 | 
						|
/*  A | B = X; */
 | 
						|
let A | B = X;
 | 
						|
 | 
						|
/*  A | (B | C) = X; */
 | 
						|
let A | (B | C) = X;
 | 
						|
 | 
						|
/* (A | B) | (C | D) = X; */
 | 
						|
let A | B | (C | D) = X;
 | 
						|
 | 
						|
/*  A | B | (C | D) = X; */
 | 
						|
let A | B | (C | D) = X;
 | 
						|
 | 
						|
/* (A | B) | C = X; */
 | 
						|
let A | B | C = X;
 | 
						|
 | 
						|
/*  A | B | C = X; */
 | 
						|
let A | B | C = X;
 | 
						|
 | 
						|
 | 
						|
/** External function declaration
 | 
						|
 *
 | 
						|
 */
 | 
						|
external f : int => int = "foo";
 | 
						|
 | 
						|
let x = {contents: 0};
 | 
						|
 | 
						|
let unitVal = x.contents = 210;
 |