1+ /*
2+ About preprocessor, please check the document at
3+ https://github.com/Hedgehog-Computing/Hedgehog-Package-Manager
14
2- async function fetchLibrary ( lib_url : string ) {
3- let raw_string_return = fetch ( lib_url , { method : 'get' } )
4- . then ( function ( body ) {
5- return body . text ( ) ;
6- } )
7- . then ( function ( data ) {
8- return data ;
9- } ) ;
10-
11- return raw_string_return ;
12- }
13-
5+ Hedgehog Lab supports three types of "*import":
6+ a. *import YOUR_FULL_URL, for example *import http://website.com/mylib/myfunction.hhs
7+ b. *import Package_Name: Function_1, Function_2, Function_3 ... the package name must be registered at https://raw.githubusercontent.com/Hedgehog-Computing/Hedgehog-Package-Manager/main/hedgehog-packages.json
8+ c. let my_Function_A = *import MY_PACKAGE: Function_A
9+ */
1410
1511async function preprocessor ( source : string ) : Promise < string > {
1612 console . log ( 'The source code after preprocessing' ) ;
17- let result = await preprocessDFS ( source , 'root' ) ;
13+ let result = await preprocessDFS ( source , 'root' ) ;
1814 console . log ( result ) ;
1915 console . log ( 'End of the source code after preprocessing' ) ;
2016 return result ;
2117}
2218
2319/*
20+ Fetch the full registered package list from
21+ https://github.com/Hedgehog-Computing/Hedgehog-Package-Manager
22+ at
23+ https://raw.githubusercontent.com/Hedgehog-Computing/Hedgehog-Package-Manager/main/hedgehog-packages.json
2424
25- Function "preprocess_dependencies" is the core function that handle the dependencies of the source code
26- by feteching the strings of libraries and adding at the top of the source code.
27-
28- For example, the input string is --
29-
30- *import http://a.com/my_function.js
31- let matrixA = mat([[1,2,3],[4,5,6]])
32- let result = my_function(matrixA)
33- print(result)
34-
35-
36- --
25+ Input: Package Name. For example, "Hedgehog-Standard-Library" or "std"
26+ Output: The root location of the package. For example, "https://raw.githubusercontent.com/Hedgehog-Computing/Hedgehog-Standard-Library/main/"
27+ */
3728
38- And the library in http://a.com/my_function.js is --
39- function my_function(matrixA: Mat):Mat
40- {
41- return matrixA * matrixA.T();
29+ function getPackageLocation ( packageName : string , theFullListInJson : string ) : string {
30+ console . log ( "Package name: " + packageName + " , full list in json: " + theFullListInJson ) ;
31+ let jsonObj = JSON . parse ( theFullListInJson ) ; let result : string [ ] = [ ] ;
32+ for ( let element of jsonObj ) {
33+ if ( element [ "name" ] === packageName || element [ "alias" ] === packageName ) { return element [ "location" ] ; }
34+ }
35+ throw "Cannot find the package with name: " + packageName ;
4236}
4337
44- --
45-
46- Then the output of preprocess function should be:
47-
48-
49- function my_function(matrixA: Mat):Mat
50- {
51- return matrixA * matrixA.T();
38+ /*
39+ Parse the registered package (the type 1 of import macro: *import PACKAGE_NAME: LIB_NAME_LIST)
40+ Input: the second part of current line splitted by "*import". For example, current line is "*import std:magic, cholesky",
41+ then the input will be "std:magic, cholesky"; if current line is "let myMagic = *import std:magic", then the input should
42+ be "std:magic, cholesky"
43+ Output: A list of string, each string represents the corresponding hhs source file
44+ */
45+ async function parseRegisterdPackage ( secondPart : string ) : Promise < Array < string > > {
46+ let returnListOfFunctions : string [ ] = [ ] ;
47+ let theFullListInJson = await fetch ( "https://raw.githubusercontent.com/Hedgehog-Computing/Hedgehog-Package-Manager/main/hedgehog-packages.json" , { method : 'get' } ) . then ( body => body . text ( ) ) ;
48+ let splittedResult = secondPart . split ( ':' ) ;
49+ if ( splittedResult . length != 2 ) throw "Invalid importing library: " + secondPart ;
50+
51+ //get the right package name and HHS list string
52+ let packageName = splittedResult [ 0 ]
53+ let importedHHSListString = splittedResult [ 1 ] ;
54+
55+ //get package location
56+ let packageLocation = getPackageLocation ( packageName . replace ( / \s / g, '' ) , theFullListInJson ) ;
57+
58+ //get the package json file: package_location + hedgehog-package.json
59+ let packageJsonFile = packageLocation + "hedgehog-package.json" ;
60+
61+ console . log ( "Package Json file: " + packageJsonFile ) ;
62+ //get the hedgehog-pacakge.json, then get the list of "includes" libraries
63+ let thePackageJsonString = await fetch ( packageJsonFile , { method : 'get' } ) . then ( body => body . text ( ) ) ;
64+ console . log ( "Package Json string: " + thePackageJsonString ) ;
65+ let thePackageJsonObj = JSON . parse ( thePackageJsonString ) ;
66+ if ( "includes" in thePackageJsonObj ) {
67+ let hhsCompleteList = thePackageJsonObj [ "includes" ] ;
68+ let setHHSCompleteList = new Set ( hhsCompleteList ) ;
69+ let importedItemList = importedHHSListString . split ( ',' ) ;
70+ for ( let eachItem of importedItemList ) {
71+ let eachItemWithoutSpace = eachItem . replace ( / \s / g, '' ) ;
72+ if ( setHHSCompleteList . has ( eachItemWithoutSpace ) ) {
73+ let currentHHSLocation = packageLocation + eachItemWithoutSpace + ".hhs" ;
74+ let currentItemSourceCode = await fetch ( currentHHSLocation , { method : 'get' } ) . then ( body => body . text ( ) ) ;
75+ returnListOfFunctions . push ( currentItemSourceCode ) ;
76+ }
77+ }
78+ }
79+ else { throw "Cannot find \"includes\" key in the hedgehog-package.json configuration file! Please add a key with name \"includes\" with a complete list of exported libraries. Exception at " + secondPart }
80+ return returnListOfFunctions ;
5281}
53- let matrixA = mat([[1,2,3],[4,5,6]])
54- let result = my_function(matrixA)
55- print(result)
56-
57-
58- or the input string is
59-
60- func = *import http://a.com/my_function.js
61- let matrixA = mat([[1,2,3],[4,5,6]])
62- let result = my_function(matrixA)
63- print(result)
64-
65- and the preprocessed string will be
6682
67- func = function my_function(matrixA: Mat):Mat
68- {
69- return matrixA * matrixA.T();
83+ // A helper function to check if a string contains URL or not. Reference: https://regexr.com/3e6m0
84+ function containsURL ( code : string ) : boolean {
85+ let expression = / ( h t t p ( s ) ? : \/ \/ .) ? ( w w w \. ) ? [ - a - z A - Z 0 - 9 @ : % . _ \+ ~ # = ] { 2 , 256 } \. [ a - z ] { 2 , 6 } \b ( [ - a - z A - Z 0 - 9 @ : % _ \+ . ~ # ? & / / = ] * ) / g;
86+ let regex = new RegExp ( expression ) ;
87+ if ( code . match ( regex ) ) return true ;
88+ return false ;
7089}
71- let matrixA = mat([[1,2,3],[4,5,6]])
72- let result = func(matrixA)
73- print(result)
74-
75- ---
76-
77-
78- Syntax: each third-party dependency line MUST start with keyword "import" following with the string of URL
79-
80- For example:
81-
82- *import http://a.com/b.js
83-
84-
85- Todo:
86- Also there is an official repo that contains all stable and official libraries at https://github.com/lidangzzz/hedgehog-lib/blob/master/stable/
87- To use an official stable libraries in stable folder, the user should add the dependency in this way (for example, a demo function at
88- https://raw.githubusercontent.com/lidangzzz/hedgehog-lib/master/stable/demo_function.js, the user should add the dependency by adding
89-
90- using demo_function
91-
92- at the beginning of the script, which is the same as
93-
94- import https://github.com/lidangzzz/hedgehog-lib/blob/master/stable/demo_function.js
95-
96- Also the preprocessor provides a way to allow user to manage the stable libraries with another repo or standalone server or mirror
97- instead of the "hedgehog-lib" repo on github by defining
98-
99- STABLE_CODE_BASE = 'http://myserver.com/my-code-base/'
100-
101- so that user can import a stable function from their owm mirror server http://myserver.com/my-code-base/demo_function.js by using
102-
103- using demo_function
104-
105- */
106-
107-
10890
10991// code is the string of code, and strCurrentCallStack is the full call stack
11092async function preprocessDFS ( code : string , strCurrentCallStack : string ) : Promise < string > {
@@ -115,40 +97,54 @@ async function preprocessDFS(code: string, strCurrentCallStack: string): Promise
11597 let returnCode = '' ;
11698
11799 //3. process each line of code
118- try {
119- for ( let i = 0 ; i < vecSplittedString . length ; i ++ ) {
100+ try {
101+ for ( let i = 0 ; i < vecSplittedString . length ; i ++ ) {
120102 returnCode += '\n' ;
121103 //3.1 if current line of code doesn't contain "*import ", just append it to returnCode
122- if ( ! vecSplittedString [ i ] . includes ( "*import " ) ) { returnCode += '\n' + vecSplittedString [ i ] ; }
104+ if ( ! vecSplittedString [ i ] . includes ( "*import " ) ) { returnCode += '\n' + vecSplittedString [ i ] ; }
123105 //3.2 otherwise, split the string by "*import ", keep the first part (if it exists), then download
124- // and fetch the second part recursively (which should be and must be a valid URL)
106+ // and fetch the second part recursively (which should be and must be a valid URL or a registered package )
125107 else {
126108 let currentString = vecSplittedString [ i ] ;
127109 let splittedResult = currentString . split ( "*import " ) ;
128- if ( splittedResult . length < 2 ) {
129- throw "Invalid current line of code for preprocessing: \n"
130- + "\nCall stack: \n" + strCurrentCallStack
131- + "\nCurrent line: " + currentString + "\n" ;
110+ if ( splittedResult . length < 2 ) {
111+ throw "Invalid current line of code for preprocessing: \n"
112+ + "\nCall stack: \n" + strCurrentCallStack
113+ + "\nCurrent line: " + currentString + "\n" ;
132114 }
133115 //3.2.1 add the first part
134116 returnCode += splittedResult [ 0 ] ;
135- console . log ( splittedResult [ 0 ] + " is added to source code" )
136- //3.2.2 download the library from URL
137- let libraryFromUrl = await fetch ( splittedResult [ 1 ] , { method : 'get' } )
138- . then ( function ( body ) {
139- let real_library = body . text ( ) ;
140- return real_library ;
141- } ) ;
142-
143- //3.2.3 get the current file information (get "FunctionABC.js" from URL string http://mywebsite/FunctionABC.js)
144- let splittedURLResult = splittedResult [ 1 ] . split ( '/' ) ;
145- let strCallStack = strCurrentCallStack + " -> " + splittedURLResult [ splittedResult . length - 1 ] ;
146-
147- //3.2.4 process the big chunk of code
148- let currentResult = await preprocessDFS ( libraryFromUrl , strCallStack ) ;
117+ //3.2.2 Is it imported from URL or from a registered package?
118+ if ( containsURL ( splittedResult [ 1 ] ) ) {
119+ //3.2.2.1 download the library from URL
120+ let libraryFromUrl = await fetch ( splittedResult [ 1 ] , { method : 'get' } )
121+ . then ( function ( body ) {
122+ let real_library = body . text ( ) ;
123+ return real_library ;
124+ } ) ;
125+
126+ //3.2.3 get the current file information (get "FunctionABC.js" from URL string http://mywebsite/FunctionABC.js)
127+ let splittedURLResult = splittedResult [ 1 ] . split ( '/' ) ;
128+ let strCallStack = strCurrentCallStack + " -> " + splittedURLResult [ splittedResult . length - 1 ] ;
129+
130+ //3.2.4 process the big chunk of code
131+ let currentResult = await preprocessDFS ( libraryFromUrl , strCallStack ) ;
132+
133+ //3.2.5 append it to the end of returnCode
134+ returnCode += currentResult + "\n" ;
135+ }
149136
150- //3.2.5 append it to the end of returnCode
151- returnCode += currentResult + "\n" ;
137+ else {
138+ // otherwise, try to split with colon and comma and fetch the registered packages
139+ let result = await parseRegisterdPackage ( splittedResult [ 1 ] ) ;
140+ let combined_result = "" ;
141+ result . forEach ( element => {
142+ combined_result += element + "\n"
143+ returnCode += combined_result + '\n' ;
144+ } ) ;
145+ }
146+
147+
152148 }
153149 }
154150 }
0 commit comments