├── .eslintrc.json ├── .github └── workflows │ └── deploy.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.py ├── ci └── upload_site.sh ├── components ├── Editor.js ├── HeadMeta.js ├── LoadLFortran.js ├── MyFooter.js ├── MyHeader.js ├── MyLayout.js ├── ResultBox.js ├── TextBox.js └── useIsMobile.js ├── environment.yml ├── next.config.js ├── package-lock.json ├── package.json ├── pages ├── _app.js └── index.js ├── public ├── favicon.ico └── vercel.svg ├── styles └── globals.css └── utils ├── ast_asr_handler.js ├── commit.json └── preinstalled_programs.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: CI 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | repository_dispatch: 10 | types: deploy 11 | pull_request: 12 | branches: 13 | - main 14 | 15 | jobs: 16 | build: 17 | 18 | runs-on: ubuntu-latest 19 | 20 | strategy: 21 | matrix: 22 | node-version: [16.x] 23 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 24 | 25 | steps: 26 | - name: Checkout Main 27 | uses: actions/checkout@v3 28 | 29 | - name: Use Node.js ${{ matrix.node-version }} 30 | uses: actions/setup-node@v3 31 | with: 32 | node-version: ${{ matrix.node-version }} 33 | cache: 'npm' 34 | 35 | - name: Install Dependencies 36 | shell: bash -l {0} 37 | run: npm i 38 | 39 | - name: Build Site 40 | shell: bash -l {0} 41 | run: | 42 | ./build.py 43 | npm run export 44 | echo "dev.lfortran.org" >> out/CNAME 45 | env: 46 | PR_NUMBER: ${{ github.event.pull_request.number }} 47 | 48 | - name: Misc Steps 49 | shell: bash -l {0} 50 | run: | 51 | mv out deploy 52 | 53 | - name: Upload Site 54 | shell: bash -l {0} 55 | run: ci/upload_site.sh 56 | env: 57 | GIT_PR_PREVIEW_PRIVATE_SSH_KEY: ${{ secrets.GIT_PR_PREVIEW_PRIVATE_SSH_KEY }} 58 | PR_NUMBER: ${{ github.event.pull_request.number }} 59 | 60 | - name: Create Deployment Comment 61 | if: ${{ github.ref != 'refs/heads/main' && github.event.pull_request.head.repo.full_name == 'lfortran/lcompilers_frontend' }} 62 | uses: peter-evans/create-or-update-comment@v2 63 | with: 64 | issue-number: ${{ github.event.pull_request.number }} 65 | body: | 66 | Your site is deployed at https://lfortran.github.io/pull_request_preview/lfortran/${{ github.event.pull_request.number }} 67 | reactions: 'rocket' 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # assets 4 | public/lfortran.js 5 | public/lfortran.wasm 6 | public/lfortran.data 7 | 8 | # dependencies 9 | /node_modules 10 | /.pnp 11 | .pnp.js 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | # /out/ 19 | 20 | # production 21 | /build 22 | /out 23 | 24 | # misc 25 | .DS_Store 26 | *.pem 27 | 28 | # debug 29 | npm-debug.log* 30 | yarn-debug.log* 31 | yarn-error.log* 32 | .pnpm-debug.log* 33 | 34 | # local env files 35 | .env*.local 36 | 37 | # vercel 38 | .vercel 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 LCompilers developers 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Getting Started 2 | 3 | First install `npm` for example using Conda: 4 | ``` 5 | conda env create -f environment.yml 6 | conda activate npm 7 | ``` 8 | Install dependencies: 9 | ``` 10 | npm install 11 | ``` 12 | 13 | Then build the website: 14 | ``` 15 | ./build.py 16 | ``` 17 | 18 | Finally serve a local version using: 19 | ``` 20 | npm run dev 21 | ``` 22 | 23 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 24 | 25 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. 26 | 27 | ## Features 28 | 29 | ### Loading Source Code from Gist or URL 30 | 31 | This feature allows users to load source code into the text box by providing either a URL or a GitHub Gist. It simplifies the process of compiling and running code from external sources, making it convenient for users to test and share code effortlessly. 32 | 33 | #### Loading Source Code from URL 34 | 35 | - Users can load source code by providing a URL directly in the format: `https://dev.lfortran.org/?code=`. 36 | - The code provided via URL can be any valid Fortran code. 37 | 38 | ##### Example URL: 39 | ``` 40 | https://dev.lfortran.org/?code=program%20hello%0A%20%20!%20This%20is%20a%20comment%20line%3B%20it%20is%20ignored%20by%20the%20compiler%0A%20%20print%20*%2C%20%27Hello%2C%20World!%27%0Aend%20program%20hello%0A 41 | ``` 42 | 43 | #### Loading Source Code from GitHub Gist 44 | 45 | - Alternatively, users can load source code from a GitHub Gist by providing the Gist URL in the format: `https://dev.lfortran.org/?gist=/`. 46 | - The compiler will fetch the raw content from the specified GitHub Gist. 47 | - **Note:** GitHub Gist takes approximately 5 minutes to update the raw content after any changes are made. As a result, there may be a delay of about 5 minutes before the updated content is reflected when loaded. 48 | 49 | ##### Example GitHub Gist URL: 50 | ``` 51 | https://dev.lfortran.org/?gist=certik/7e2652943bbff7f0d0963dd4fcf1813a 52 | ``` 53 | 54 | #### Mutual Exclusivity 55 | 56 | - Users should be aware that if both a URL and a GitHub Gist are provided, the `code` parameter is given preference. Only the code provided via the `code` parameter will be considered for compilation. 57 | 58 | This feature enhances the versatility of the LFortran compiler, enabling users to seamlessly compile and run Fortran code from external sources without needing to download or manage local files. 59 | 60 | 61 | ## Learn More 62 | 63 | To learn more about Next.js, take a look at the following resources: 64 | 65 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 66 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 67 | -------------------------------------------------------------------------------- /build.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import json 5 | import subprocess as sp 6 | 7 | def run_cmd(cmd, cwd=None): 8 | print(f"+ {cmd}") 9 | process = sp.run(cmd, shell=True, cwd=cwd) 10 | if process.returncode != 0: 11 | print("Command failed.") 12 | exit(1) 13 | 14 | def download_lfortran_file(commit, filename): 15 | base_url = "https://lfortran.github.io/wasm_builds" 16 | run_cmd(f'curl "{base_url}/{commit["build_type"]}/{commit["id"]}/{filename}" -o public/{filename}') 17 | 18 | commit = json.load(open("utils/commit.json")) 19 | 20 | download_lfortran_file(commit, "lfortran.js") 21 | download_lfortran_file(commit, "lfortran.wasm") 22 | download_lfortran_file(commit, "lfortran.data") 23 | 24 | if os.getenv("GITHUB_REF") is None or os.getenv("GITHUB_REF") == "refs/heads/main": 25 | # For local development environment or for production environment, 26 | # the base path is empty 27 | os.environ["SITE_BASE_PATH"] = "" 28 | else: 29 | # For test environment 30 | os.environ["SITE_BASE_PATH"] = f"/pull_request_preview/lfortran/{os.getenv('PR_NUMBER')}" 31 | 32 | run_cmd("npm run build") 33 | -------------------------------------------------------------------------------- /ci/upload_site.sh: -------------------------------------------------------------------------------- 1 | #/usr/bin/bash 2 | 3 | set -ex 4 | 5 | git_ref=${GITHUB_REF} 6 | 7 | mkdir ~/.ssh 8 | chmod 700 ~/.ssh 9 | ssh-keyscan github.com >> ~/.ssh/known_hosts 10 | eval "$(ssh-agent -s)" 11 | 12 | if [[ ${git_ref} == "refs/heads/main" ]]; then 13 | # Production version - pipeline triggered from main branch 14 | deploy_repo_push="origin" 15 | 16 | D=".." 17 | cp deploy/ $D/deploy -r 18 | git reset --hard 19 | git clean -dfx 20 | git fetch origin 21 | git checkout gh-pages 22 | rm -rf * 23 | mv $D/deploy/* . 24 | touch .nojekyll 25 | else 26 | # Test version - pipeline triggered from pull request 27 | deploy_repo_pull="https://github.com/lfortran/pull_request_preview.git" 28 | deploy_repo_push="git@github.com:lfortran/pull_request_preview.git" 29 | 30 | D=`pwd` 31 | 32 | mkdir $HOME/repos 33 | cd $HOME/repos 34 | 35 | git clone ${deploy_repo_pull} pr_preview 36 | cd pr_preview 37 | 38 | git fetch origin 39 | git checkout gh-pages 40 | 41 | mkdir -p lfortran/$PR_NUMBER 42 | cd lfortran/$PR_NUMBER 43 | rm -rf * 44 | mv $D/deploy/* . 45 | fi 46 | 47 | git config user.email "noreply@deploy" 48 | git config user.name "Deploy" 49 | 50 | git add . 51 | COMMIT_MESSAGE="Deploying on $(date "+%Y-%m-%d %H:%M:%S")" 52 | git commit -m "${COMMIT_MESSAGE}" 53 | 54 | if [[ ${git_ref} != "refs/heads/main" ]]; then 55 | if [[ "${GIT_PR_PREVIEW_PRIVATE_SSH_KEY}" == "" ]]; then 56 | echo "Note: GIT_PR_PREVIEW_PRIVATE_SSH_KEY is empty, skipping..." 57 | exit 0 58 | fi 59 | ssh-add <(echo "$GIT_PR_PREVIEW_PRIVATE_SSH_KEY" | base64 -d) 60 | fi 61 | 62 | git push ${deploy_repo_push} gh-pages:gh-pages 63 | -------------------------------------------------------------------------------- /components/Editor.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import AceEditor from "react-ace"; 3 | 4 | import "ace-builds/src-noconflict/mode-java"; 5 | import "ace-builds/src-noconflict/mode-fortran"; 6 | import "ace-builds/src-noconflict/theme-github"; 7 | import "ace-builds/src-noconflict/theme-monokai"; 8 | import "ace-builds/src-noconflict/ext-language_tools"; 9 | 10 | function Editor({sourceCode, setSourceCode}) { 11 | return ( 12 | setSourceCode(code)} 16 | name="UNIQUE_ID_OF_DIV" 17 | editorProps={{ $blockScrolling: true }} 18 | value={sourceCode} 19 | width="100%" 20 | height="100%" 21 | showPrintMargin={false} 22 | style={{ 23 | fontFamily: '"Fira code", "Fira Mono", monospace', 24 | fontSize: 14, 25 | // minHeight: "100%", 26 | // border: "0.1px solid black" 27 | }} 28 | /> 29 | ) 30 | } 31 | 32 | export default Editor; 33 | -------------------------------------------------------------------------------- /components/HeadMeta.js: -------------------------------------------------------------------------------- 1 | import Head from "next/head"; 2 | 3 | function HeadMeta() { 4 | return ( 5 | 6 | LFortran 7 | 11 | 12 | 16 | 17 | 18 | ); 19 | } 20 | 21 | export default HeadMeta; 22 | -------------------------------------------------------------------------------- /components/LoadLFortran.js: -------------------------------------------------------------------------------- 1 | import Script from "next/script"; 2 | import { useRouter } from "next/router"; 3 | import { useCallback, useEffect } from "react"; 4 | 5 | // lfortran exported functions 6 | function getLfortranExportedFuncs() { 7 | return new Promise((resolve, reject) => { 8 | Module.onRuntimeInitialized = function () { 9 | resolve({ 10 | emit_ast_from_source: Module.cwrap("emit_ast_from_source", "string", ["string"]), 11 | emit_asr_from_source: Module.cwrap("emit_asr_from_source", "string", ["string"]), 12 | emit_wat_from_source: Module.cwrap("emit_wat_from_source", "string", ["string"]), 13 | emit_cpp_from_source: Module.cwrap("emit_cpp_from_source", "string", ["string"]), 14 | emit_py_from_source: Module.cwrap("emit_wat_from_source", "string", ["string"]), 15 | emit_wasm_from_source: Module.cwrap("emit_wasm_from_source", "string", ["string"]), 16 | }); 17 | }; 18 | }); 19 | } 20 | 21 | var memory; 22 | function define_imports(outputBuffer, exit_code, stdout_print) { 23 | const flushBuffer = () => { 24 | stdout_print(outputBuffer.join("")); 25 | outputBuffer.length = 0; 26 | } 27 | const fd_write = (file_type, iov_location, no_of_iovs, return_val_mem_loc) => { 28 | const mem_data = new DataView(memory.buffer, iov_location, Int32Array.BYTES_PER_ELEMENT * 2); 29 | const strLoc = mem_data.getInt32(0, true); 30 | const strLen = mem_data.getInt32(4, true); 31 | const s = new TextDecoder("utf8").decode(new Uint8Array(memory.buffer, strLoc, strLen)); 32 | outputBuffer.push(s); 33 | return 0; 34 | } 35 | const proc_exit = (exit_code_val) => exit_code.val = exit_code_val; 36 | const cpu_time = (time) => (Date.now() / 1000); // Date.now() returns milliseconds, so divide by 1000 37 | const show_image = (cols, rows, arr) => { 38 | var arr2D_data = new DataView(memory.buffer, arr, Int32Array.BYTES_PER_ELEMENT * rows * cols); 39 | var canvas = document.createElement("CANVAS"); 40 | canvas.width = cols; 41 | canvas.height = rows; 42 | var ctx = canvas.getContext("2d"); 43 | var imgData = ctx.createImageData(cols, rows); 44 | for (var i = 0; i < imgData.data.length; i += 4) { 45 | imgData.data[i + 0] = arr2D_data.getInt32(i, true); 46 | imgData.data[i + 1] = arr2D_data.getInt32(i, true); 47 | imgData.data[i + 2] = arr2D_data.getInt32(i, true); 48 | imgData.data[i + 3] = 255; // alpha channel (from 0-255), 0 is transparent and 255 is fully visible 49 | } 50 | ctx.putImageData(imgData, 0, 0); 51 | outputBuffer.push(`constructed image\n`) 52 | flushBuffer(); 53 | } 54 | const show_image_color = (cols, rows, arr) => { 55 | var arr2D_data = new DataView(memory.buffer, arr, Int32Array.BYTES_PER_ELEMENT * 4 * rows * cols); 56 | var canvas = document.createElement("CANVAS"); 57 | canvas.width = cols; 58 | canvas.height = rows; 59 | var ctx = canvas.getContext("2d"); 60 | var imgData = ctx.createImageData(cols, rows); 61 | // The data in DataView is stored as i32 per channel, while it 62 | // should be i8. Currently we have to copy the i32 integer and assign 63 | // it to the canvas' i8 integer. We have to index it with 4*i, because 64 | // the getInt32 method accepts a byte index. 65 | for (var i = 0; i < imgData.data.length; i++) { 66 | imgData.data[i] = arr2D_data.getInt32(4*i, true); 67 | } 68 | ctx.putImageData(imgData, 0, 0); 69 | outputBuffer.push(`constructed image\n`) 70 | flushBuffer(); 71 | } 72 | var imports = { 73 | wasi_snapshot_preview1: { 74 | /* wasi functions */ 75 | fd_write: fd_write, 76 | proc_exit: proc_exit, 77 | }, 78 | js: { 79 | /* custom functions */ 80 | cpu_time: cpu_time, 81 | show_img: show_image, 82 | show_img_color: show_image_color 83 | }, 84 | }; 85 | return imports; 86 | } 87 | 88 | async function setup_lfortran_funcs(lfortran_funcs, myPrint) { 89 | const compiler_funcs = await getLfortranExportedFuncs(); 90 | 91 | lfortran_funcs.emit_ast_from_source = function (source_code) { 92 | try { return compiler_funcs.emit_ast_from_source(source_code); } 93 | catch (e) { console.log(e); myPrint(e + "\nERROR: AST could not be generated from the code"); return 0; } 94 | } 95 | 96 | lfortran_funcs.emit_asr_from_source = function (source_code) { 97 | try { return compiler_funcs.emit_asr_from_source(source_code); } 98 | catch (e) { console.log(e); myPrint(e + "\nERROR: ASR could not be generated from the code"); return 0; } 99 | } 100 | 101 | lfortran_funcs.emit_wat_from_source = function (source_code) { 102 | try { return compiler_funcs.emit_wat_from_source(source_code); } 103 | catch (e) { console.log(e); myPrint(e + "\nERROR: WAT could not be generated from the code"); return 0; } 104 | } 105 | 106 | lfortran_funcs.emit_cpp_from_source = function (source_code) { 107 | try { return compiler_funcs.emit_cpp_from_source(source_code); } 108 | catch (e) { console.log(e); myPrint(e + "\nERROR: CPP could not be generated from the code"); return 0; } 109 | } 110 | 111 | lfortran_funcs.emit_py_from_source = function (source_code) { 112 | try { return compiler_funcs.emit_py_from_source(source_code); } 113 | catch (e) { console.log(e); myPrint(e + "\nERROR: LLVM could not be generated from the code"); return 0; } 114 | } 115 | 116 | lfortran_funcs.compile_code = function (source_code) { 117 | try { 118 | return compiler_funcs.emit_wasm_from_source(source_code); 119 | } 120 | catch (e) { 121 | console.log(e); 122 | myPrint(e + "\nERROR: The code could not be compiled. Either there is a compile-time error or there is an issue at our end.") 123 | return 0; 124 | } 125 | 126 | }; 127 | 128 | lfortran_funcs.execute_code = async function (bytes, stdout_print) { 129 | var exit_code = {val: 1}; /* non-zero exit code */ 130 | var outputBuffer = []; 131 | var imports = define_imports(outputBuffer, exit_code, stdout_print); 132 | var start_exec, end_exec; 133 | const printResults = () => { 134 | const duration_exec = end_exec - start_exec; 135 | const duration_compile = sessionStorage.getItem("duration_compile"); 136 | outputBuffer.push(`\nCompilation time: ${duration_compile} ms`); 137 | outputBuffer.push(`\nExecution time: ${duration_exec} ms`); 138 | stdout_print(outputBuffer.join("")); 139 | } 140 | try { 141 | var res = await WebAssembly.instantiate(bytes, imports); 142 | memory = res.instance.exports.memory; 143 | start_exec = performance.now(); 144 | res.instance.exports._start(); 145 | end_exec = performance.now(); 146 | printResults(); 147 | } catch(err_msg) { 148 | end_exec = performance.now(); 149 | printResults(); 150 | if (exit_code.val == 0) { 151 | return; 152 | } 153 | console.log(err_msg); 154 | stdout_print(`\n${err_msg}\nERROR: The code could not be executed. Either there is a runtime error or there is an issue at our end.`); 155 | } 156 | }; 157 | } 158 | 159 | function LoadLFortran({ 160 | moduleReady, 161 | setModuleReady, 162 | lfortran_funcs, 163 | openNotification, 164 | myPrint, 165 | }) { 166 | 167 | const { basePath } = useRouter(); 168 | 169 | useEffect(() => { 170 | window.Module = { 171 | locateFile: (filePath) => `${basePath}/${filePath}` 172 | } 173 | return () => { window.Module = null } 174 | }, [basePath]); 175 | 176 | const setupLFortran = useCallback(async () => { 177 | await setup_lfortran_funcs(lfortran_funcs, myPrint); 178 | setModuleReady(true); 179 | openNotification("LFortran Module Initialized!", "bottomRight"); 180 | console.log("LFortran Module Initialized!"); 181 | }, [moduleReady]); // update the callback if the state changes 182 | 183 | return ( 184 |
185 | 186 |
187 | ); 188 | } 189 | 190 | export default LoadLFortran; 191 | -------------------------------------------------------------------------------- /components/MyFooter.js: -------------------------------------------------------------------------------- 1 | import { Footer } from "antd/lib/layout/layout"; 2 | import commit from "../utils/commit.json" 3 | 4 | function MyFooter() { 5 | return ( 6 | 20 | ); 21 | } 22 | 23 | export default MyFooter; 24 | -------------------------------------------------------------------------------- /components/MyHeader.js: -------------------------------------------------------------------------------- 1 | import { HomeOutlined } from '@ant-design/icons'; 2 | import { Menu } from 'antd'; 3 | import { useState } from "react"; 4 | import HeadMeta from './HeadMeta'; 5 | 6 | const items = [ 7 | { 8 | label: <> LFortran, 9 | key: "1" 10 | } 11 | ] 12 | function MyHeader() { 13 | const [current, setCurrent] = useState("1") 14 | return ( 15 | <> 16 | 17 | 18 | 19 | ); 20 | } 21 | 22 | export default MyHeader; 23 | -------------------------------------------------------------------------------- /components/MyLayout.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | 3 | import MyHeader from "./MyHeader"; 4 | import MyFooter from "./MyFooter"; 5 | import { Layout } from "antd"; 6 | import { Content } from "antd/lib/layout/layout"; 7 | 8 | function MyLayout({ children }) { 9 | 10 | useEffect(() => { 11 | let script = document.createElement("script"); 12 | script.src = "//gc.zgo.at/count.js"; 13 | script.async = true; 14 | script.setAttribute("data-goatcounter", "https://lfortran.goatcounter.com/count") 15 | document.body.appendChild(script); 16 | return () => { 17 | document.body.removeChild(script); 18 | } 19 | }); 20 | 21 | return ( 22 | 23 | 24 | 25 | {children} 26 | 27 | 28 | 29 | ); 30 | } 31 | 32 | export default MyLayout; 33 | -------------------------------------------------------------------------------- /components/ResultBox.js: -------------------------------------------------------------------------------- 1 | import { Button } from "antd"; 2 | import { CopyOutlined } from "@ant-design/icons"; 3 | import { Segmented } from "antd"; 4 | 5 | function ResultBox({ activeTab, output, handleUserTabChange, myHeight, openNotification }) { 6 | function copyTextToClipboard() { 7 | const parser = new DOMParser(); 8 | const doc = parser.parseFromString(output, 'text/html'); 9 | navigator.clipboard.writeText(doc.documentElement.textContent); 10 | openNotification(`${activeTab} output copied`, "bottomRight"); 11 | } 12 | return ( 13 |
14 | handleUserTabChange(key)} 20 | /> 21 | 24 |
25 |                 
26 | 27 |
28 |
29 |
30 | ); 31 | } 32 | 33 | export default ResultBox; 34 | -------------------------------------------------------------------------------- /components/TextBox.js: -------------------------------------------------------------------------------- 1 | import { Button, Tabs, Dropdown, Menu, Space } from "antd"; 2 | const { TabPane } = Tabs; 3 | import { DownOutlined, PlayCircleOutlined } from "@ant-design/icons"; 4 | import preinstalled_programs from "../utils/preinstalled_programs"; 5 | import dynamic from 'next/dynamic' 6 | const Editor = dynamic(import('./Editor'), { 7 | ssr: false 8 | }) 9 | 10 | function TextBox({ disabled, sourceCode, setSourceCode, exampleName, setExampleName, activeTab, handleUserTabChange, myHeight }) { 11 | var menu_items = []; 12 | for (let category in preinstalled_programs) { 13 | var category_examples = [] 14 | for (let example in preinstalled_programs[category]) { 15 | category_examples.push({ 16 | key: example, 17 | label: example, 18 | onClick: () => { 19 | setSourceCode(preinstalled_programs[category][example]); 20 | setExampleName(example); 21 | } 22 | }); 23 | } 24 | 25 | menu_items.push({ 26 | key: category, 27 | label: category, 28 | children: category_examples 29 | }); 30 | } 31 | 32 | const examples_menu = (); 33 | const extraOperations = { 34 | right: , 35 | left: 36 | e.preventDefault()}> 37 | 38 | Examples 39 | 40 | 41 | 42 | }; 43 | 44 | return ( 45 |
46 | 47 | 48 | 52 | 53 | 54 | 55 |
56 | ); 57 | } 58 | 59 | export default TextBox; 60 | -------------------------------------------------------------------------------- /components/useIsMobile.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | export function useIsMobile() { 4 | const [isMobile, setIsMobile] = useState(false); 5 | 6 | useEffect(() => { 7 | const checkIsMobile = () => { 8 | // const userAgent = 9 | // typeof window !== 'undefined' && window.navigator.userAgent; 10 | // const mobileRegex = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i; 11 | // const isMobile = mobileRegex.test(userAgent); 12 | const isMobile = (window.innerWidth < 768); 13 | setIsMobile(isMobile); 14 | }; 15 | 16 | checkIsMobile(); 17 | 18 | window.addEventListener('resize', checkIsMobile); 19 | 20 | return () => { 21 | window.removeEventListener('resize', checkIsMobile); 22 | }; 23 | }, []); 24 | 25 | return isMobile; 26 | } 27 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: npm 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - nodejs=16.17.1 6 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | basePath: process.env.SITE_BASE_PATH, 5 | } 6 | 7 | module.exports = nextConfig 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lcompilers_frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "export": "next export", 9 | "start": "next start", 10 | "lint": "next lint" 11 | }, 12 | "dependencies": { 13 | "ansi_up": "^5.1.0", 14 | "antd": "^4.21.3", 15 | "json-loader": "^0.5.7", 16 | "next": "12.1.6", 17 | "react": "18.2.0", 18 | "react-ace": "^10.1.0", 19 | "react-dom": "18.2.0" 20 | }, 21 | "devDependencies": { 22 | "eslint": "8.18.0", 23 | "eslint-config-next": "12.1.6" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /pages/_app.js: -------------------------------------------------------------------------------- 1 | import "../styles/globals.css"; 2 | 3 | import MyLayout from "../components/MyLayout"; 4 | 5 | function MyApp({ Component, pageProps }) { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | } 12 | 13 | export default MyApp; 14 | -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | import TextBox from "../components/TextBox"; 2 | import ResultBox from "../components/ResultBox"; 3 | import LoadLFortran from "../components/LoadLFortran"; 4 | import preinstalled_programs from "../utils/preinstalled_programs"; 5 | import { useIsMobile } from "../components/useIsMobile"; 6 | 7 | import { useState, useEffect } from "react"; 8 | import { Col, Row, Spin } from "antd"; 9 | import { notification } from "antd"; 10 | import { LoadingOutlined } from "@ant-design/icons"; 11 | import AnsiUp from "ansi_up"; 12 | 13 | var ansi_up = new AnsiUp(); 14 | 15 | const antIcon = ( 16 | 22 | ); 23 | 24 | const openNotification = (msg, placement) => { 25 | notification.info({ 26 | message: msg, 27 | placement, 28 | }); 29 | }; 30 | 31 | var lfortran_funcs = { 32 | emit_ast_from_source: null, 33 | emit_asr_from_source: null, 34 | emit_wat_from_source: null, 35 | emit_wasm_from_source: null, 36 | emit_cpp_from_source: null, 37 | emit_py_from_source: null, 38 | compile_code: null, 39 | execute_code: null, 40 | }; 41 | 42 | export default function Home() { 43 | const [moduleReady, setModuleReady] = useState(false); 44 | const [sourceCode, setSourceCode] = useState(""); 45 | const [exampleName, setExampleName] = useState("main"); 46 | const [activeTab, setActiveTab] = useState("STDOUT"); 47 | const [output, setOutput] = useState(""); 48 | const [dataFetch, setDataFetch] = useState(false); 49 | const isMobile = useIsMobile(); 50 | 51 | const myHeight = ((!isMobile) ? "calc(100vh - 170px)" : "calc(50vh - 85px)"); 52 | 53 | useEffect(() => { 54 | setSourceCode(""); 55 | fetchData(); 56 | }, []); 57 | 58 | useEffect(() => { 59 | if(moduleReady && dataFetch) { 60 | handleUserTabChange("STDOUT"); 61 | } 62 | }, [moduleReady, dataFetch]); 63 | 64 | async function fetchData() { 65 | const url = window.location.search; 66 | const gist = "https://gist.githubusercontent.com/"; 67 | const urlParams = new URLSearchParams(url); 68 | 69 | if (urlParams.get("code")) { 70 | setSourceCode(decodeURIComponent(urlParams.get("code"))); 71 | setDataFetch(true); 72 | } else if (urlParams.get("gist")) { 73 | const gistUrl = gist + urlParams.get("gist") + "/raw/"; 74 | fetch(gistUrl, {cache: "no-store"}) 75 | .then((response) => response.text()) 76 | .then((data) => { 77 | setSourceCode(data); 78 | setDataFetch(true); 79 | openNotification( 80 | "Source Code loaded from gist.", 81 | "bottomRight" 82 | ); 83 | }) 84 | .catch((error) => { 85 | console.error("Error fetching data:", error); 86 | openNotification("error fetching .", "bottomRight"); 87 | }); 88 | } else { 89 | setSourceCode(preinstalled_programs.basic.mandelbrot); 90 | setDataFetch(true); 91 | if(urlParams.size>0){ 92 | openNotification("The URL contains an invalid parameter.", "bottomRight"); 93 | } 94 | } 95 | } 96 | 97 | async function handleUserTabChange(key) { 98 | if (key == "STDOUT") { 99 | if(sourceCode.trim() === ""){ 100 | setOutput("No Source Code to compile"); 101 | setActiveTab(key); 102 | return; 103 | } 104 | const start_compile = performance.now(); 105 | const wasm_bytes_response = lfortran_funcs.compile_code(sourceCode); 106 | const end_compile = performance.now(); 107 | const duration_compile = end_compile - start_compile; 108 | sessionStorage.setItem("duration_compile", duration_compile); 109 | if (wasm_bytes_response) { 110 | const [exit_code, ...compile_result] = wasm_bytes_response.split(","); 111 | if (exit_code !== "0") { 112 | // print compile-time error found by lfortran to output 113 | setOutput(ansi_up.ansi_to_html(compile_result) + `\nCompilation Time: ${duration_compile} ms`); 114 | } 115 | else { 116 | var stdout = []; 117 | const exec_res = await lfortran_funcs.execute_code( 118 | new Uint8Array(compile_result), 119 | (text) => stdout.push(text) 120 | ); 121 | setOutput(stdout.join("")); 122 | } 123 | } 124 | } else if (key == "AST") { 125 | const res = lfortran_funcs.emit_ast_from_source(sourceCode); 126 | if (res) { 127 | setOutput(ansi_up.ansi_to_html(res)); 128 | } 129 | } else if (key == "ASR") { 130 | const res = lfortran_funcs.emit_asr_from_source(sourceCode); 131 | if (res) { 132 | setOutput(ansi_up.ansi_to_html(res)); 133 | } 134 | } else if (key == "WAT") { 135 | const res = lfortran_funcs.emit_wat_from_source(sourceCode); 136 | if (res) { 137 | setOutput(ansi_up.ansi_to_html(res)); 138 | } 139 | } else if (key == "CPP") { 140 | const res = lfortran_funcs.emit_cpp_from_source(sourceCode); 141 | if (res) { 142 | setOutput(ansi_up.ansi_to_html(res)); 143 | } 144 | } else if (key == "PY") { 145 | setOutput("Support for PY is not yet enabled"); 146 | } else { 147 | console.log("Unknown key:", key); 148 | setOutput("Unknown key: " + key); 149 | } 150 | setActiveTab(key); 151 | } 152 | 153 | return ( 154 | <> 155 | 162 | 163 | 164 | 165 | 175 | 176 | 177 | {moduleReady ? ( 178 | 185 | ) : ( 186 |
187 | 195 |
196 | )} 197 | 198 |
199 | 200 | ); 201 | } 202 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lfortran/lcompilers_frontend/ed5ec4b100ce3c40417c7d52c714cf3bc33cebb7/public/favicon.ico -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /styles/globals.css: -------------------------------------------------------------------------------- 1 | /* @import '~antd/dist/antd.dark.css'; */ 2 | @import "~antd/dist/antd.css"; 3 | 4 | .ant-tabs-content{ 5 | height: 100%; 6 | } 7 | -------------------------------------------------------------------------------- /utils/ast_asr_handler.js: -------------------------------------------------------------------------------- 1 | function remove_ansi_escape_seq(text) { 2 | return text.replace(/(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]/g, ""); 3 | } 4 | 5 | export default remove_ansi_escape_seq; 6 | -------------------------------------------------------------------------------- /utils/commit.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "b5e05bd3a", 3 | "build_type": "release" 4 | } 5 | -------------------------------------------------------------------------------- /utils/preinstalled_programs.js: -------------------------------------------------------------------------------- 1 | var preinstalled_programs = { 2 | basic: { 3 | expr2 : `program expr2 4 | implicit none 5 | 6 | integer :: x 7 | 8 | x = (2+3)*5 9 | print *, x 10 | end program`, 11 | mandelbrot: `program mandelbrot 12 | integer, parameter :: Nx = 600, Ny = 450, n_max = 255, dp=kind(0.d0) 13 | real(dp), parameter :: xcenter = -0.5_dp, ycenter = 0.0_dp, & 14 | width = 4, height = 3, dx_di = width/Nx, dy_dj = -height/Ny, & 15 | x_offset = xcenter - (Nx+1)*dx_di/2, y_offset = ycenter - (Ny+1)*dy_dj/2 16 | integer :: image(Nx,Ny), image_color(4,Nx,Ny), palette(3,4), i, j, n, idx 17 | real(dp) :: x, y, x_0, y_0, x_sqr, y_sqr 18 | interface 19 | subroutine show_img(w, h, A) bind(js) 20 | integer, intent(in) :: w, h 21 | integer, intent(in) :: A(w,h) 22 | end subroutine 23 | subroutine show_img_color(w, h, A) bind(js) 24 | integer, intent(in) :: w, h 25 | integer, intent(in) :: A(4,w,h) 26 | end subroutine 27 | end interface 28 | do j = 1, Ny 29 | y_0 = y_offset + dy_dj * j 30 | do i = 1, Nx 31 | x_0 = x_offset + dx_di * i 32 | x = 0; y = 0; n = 0 33 | do 34 | x_sqr = x ** 2; y_sqr = y ** 2 35 | if (x_sqr + y_sqr > 4 .or. n == n_max) then 36 | image(i,j) = 255-n 37 | exit 38 | end if 39 | y = y_0 + 2 * x * y 40 | x = x_0 + x_sqr - y_sqr 41 | n = n + 1 42 | end do 43 | end do 44 | end do 45 | palette(1,1) = 0; palette(2,1) = 135; palette(3,1) = 68 46 | palette(1,2) = 0; palette(2,2) = 87; palette(3,2) = 231 47 | palette(1,3) = 214; palette(2,3) = 45; palette(3,3) = 32 48 | palette(1,4) = 255; palette(2,4) = 167; palette(3,4) = 0 49 | do j = 1, Ny 50 | do i = 1, Nx 51 | idx = image(i,j) - (image(i,j)/4)*4 + 1 52 | image_color(1,i,j) = palette(1,idx) ! Red 53 | image_color(2,i,j) = palette(2,idx) ! Green 54 | image_color(3,i,j) = palette(3,idx) ! Blue 55 | image_color(4,i,j) = 255 ! Alpha 56 | end do 57 | end do 58 | print *, "The Mandelbrot image in color:" 59 | call show_img_color(Nx, Ny, image_color) 60 | print *, "The Mandelbrot image in grayscale:" 61 | call show_img(Nx, Ny, image) 62 | print *, "Done." 63 | end program mandelbrot` 64 | }, 65 | experimental: { 66 | template_add: `module template_add_01_m 67 | implicit none 68 | private 69 | public :: add_t 70 | 71 | requirement R(T, F) 72 | type, deferred :: T 73 | function F(x, y) result(z) 74 | type(T), intent(in) :: x, y 75 | type(T) :: z 76 | end function 77 | end requirement 78 | 79 | template add_t(T, F) 80 | require :: R(T, F) 81 | private 82 | public :: add_generic 83 | contains 84 | function add_generic(x, y) result(z) 85 | type(T), intent(in) :: x, y 86 | type(T) :: z 87 | z = F(x, y) 88 | end function 89 | end template 90 | 91 | contains 92 | 93 | real function func_arg_real(x, y) result(z) 94 | real, intent(in) :: x, y 95 | z = x + y 96 | end function 97 | 98 | integer function func_arg_int(x, y) result(z) 99 | integer, intent(in) :: x, y 100 | z = x + y 101 | end function 102 | 103 | subroutine test_template() 104 | instantiate add_t(real, func_arg_real), only: add_real => add_generic 105 | real :: x, y 106 | integer :: a, b 107 | x = 5.1 108 | y = 7.2 109 | print*, "The result is ", add_real(x, y) 110 | if (abs(add_real(x, y) - 12.3) > 1e-5) error stop 111 | 112 | instantiate add_t(integer, func_arg_int), only: add_integer => add_generic 113 | a = 5 114 | b = 9 115 | print*, "The result is ", add_integer(a, b) 116 | if (add_integer(a, b) /= 14) error stop 117 | end subroutine 118 | end module 119 | 120 | program template_add_01 121 | use template_add_01_m 122 | implicit none 123 | 124 | call test_template() 125 | 126 | end program`, 127 | template_nested: `module template_nested_m 128 | implicit none 129 | private 130 | public :: add_t 131 | 132 | requirement R(T, F) 133 | type, deferred :: T 134 | function F(x, y) result(z) 135 | type(T), intent(in) :: x, y 136 | type(T) :: z 137 | end function 138 | end requirement 139 | 140 | template add_t(T, F) 141 | require :: R(T, F) 142 | private 143 | public :: add_generic 144 | contains 145 | function add_generic(x, y) result(z) 146 | type(T), intent(in) :: x, y 147 | type(T) :: z 148 | z = F(x, y) 149 | end function 150 | function call_add_generic(x, y) result(z) 151 | type(T), intent(in) :: x, y 152 | type(T) :: z 153 | z = add_generic(x, y) 154 | end function 155 | end template 156 | 157 | contains 158 | 159 | real function func_arg_real(x, y) result(z) 160 | real, intent(in) :: x, y 161 | z = x + y 162 | end function 163 | 164 | subroutine test_template() 165 | instantiate add_t(real, func_arg_real), only: add_real => call_add_generic 166 | real :: x, y 167 | integer :: a, b 168 | x = 5.1 169 | y = 7.2 170 | print*, "The result is ", add_real(x, y) 171 | if (abs(add_real(x, y) - 12.3) > 1e-5) error stop 172 | end subroutine 173 | end module 174 | 175 | program template_nested 176 | use template_nested_m 177 | implicit none 178 | 179 | call test_template() 180 | 181 | end program template_nested`, 182 | template_travel: `module template_travel_01_math 183 | 184 | implicit none 185 | private 186 | public :: add_real, slash_real 187 | 188 | contains 189 | 190 | pure function add_real(x, y) result(total) 191 | real, intent(in) :: x, y 192 | real :: total 193 | total = x + y 194 | end function 195 | 196 | pure function slash_real(x, y) result(total) 197 | real, intent(in) :: x, y 198 | real :: total 199 | total = x / y 200 | end function 201 | 202 | end module 203 | 204 | module template_travel_01_travel 205 | 206 | use template_travel_01_math 207 | implicit none 208 | private 209 | public :: travel_tmpl 210 | 211 | requirement operations(D, T, S, plus_D, plus_T, D_divided_by_T, D_divided_by_S) 212 | type, deferred :: D 213 | type, deferred :: T 214 | type, deferred :: S 215 | 216 | pure function plus_D(l, r) result(total) 217 | type(D), intent(in) :: l, R 218 | type(D) :: total 219 | end function 220 | 221 | pure function plus_T(l, r) result(total) 222 | type(T), intent(in) :: l, R 223 | type(T) :: total 224 | end function 225 | 226 | pure function D_divided_by_T(n, d) result(quotient) 227 | type(D), intent(in) :: n 228 | type(T), intent(in) :: d 229 | type(S) :: quotient 230 | end function 231 | 232 | pure function D_divided_by_S(n, d) result(quotient) 233 | type(D), intent(in) :: n 234 | type(S), intent(in) :: d 235 | type(T) :: quotient 236 | end function 237 | end requirement 238 | 239 | template travel_tmpl(D, T, S, plus_D, plus_T, D_divided_by_T, D_divided_by_S) 240 | require :: operations(D, T, S, plus_D, plus_T, D_divided_by_T, D_divided_by_S) 241 | private 242 | public :: avg_S_from_T 243 | contains 244 | pure function avg_S_from_T(d1, t1, d2, t2) result(avg) 245 | type(D), intent(in) :: d1, d2 246 | type(T), intent(in) :: t1, t2 247 | type(S) :: avg 248 | avg = D_divided_by_T(plus_D(d1, d2), plus_T(t1, t2)) 249 | end function 250 | 251 | pure function avg_S_from_S(d1, s1, d2, s2) result(avg) 252 | type(D), intent(in) :: d1, d2 253 | type(S), intent(in) :: s1, s2 254 | type(S) :: avg 255 | avg = avg_S_from_T(d1, D_divided_by_S(d1, s1), d2, D_divided_by_S(d2, s2)) 256 | end function 257 | end template 258 | 259 | end module 260 | 261 | module template_travel_01_m 262 | 263 | use template_travel_01_math 264 | use template_travel_01_travel 265 | implicit none 266 | 267 | contains 268 | 269 | subroutine test_template() 270 | instantiate travel_tmpl(real, real, real, add_real, add_real, slash_real, slash_real), & 271 | only: avg_real_S_from_T => avg_S_from_T 272 | instantiate travel_tmpl(real, real, real, add_real, add_real, slash_real, slash_real), & 273 | only: avg_real_S_from_S => avg_S_from_S 274 | real :: s1, s2 275 | s1 = avg_real_S_from_T(1.0, 3.0, 1.5, 4.0) 276 | s2 = avg_real_S_from_S(1.1, 0.5, 2.0, 0.75) 277 | print *, "s1=", s1 278 | print *, "s2=", s2 279 | end subroutine 280 | 281 | end module 282 | 283 | program template_travel_01 284 | use template_travel_01_m 285 | implicit none 286 | 287 | call test_template() 288 | 289 | end program template_travel_01 290 | `, 291 | template_triple: `module Math_integer_m 292 | 293 | implicit none 294 | private 295 | public :: add_integer 296 | 297 | contains 298 | 299 | pure function add_integer(x, y) result(result) 300 | integer, intent(in) :: x, y 301 | integer :: result 302 | result = x + y 303 | end function 304 | 305 | pure function minus_integer(x, y) result(result) 306 | integer, intent(in) :: x, y 307 | integer :: result 308 | result = x - y 309 | end function 310 | 311 | pure function max_integer(x, y) result(result) 312 | integer, intent(in) :: x, y 313 | integer :: result 314 | result = max(x, y) 315 | end function 316 | 317 | pure function min_integer(x, y) result(result) 318 | integer, intent(in) :: x, y 319 | integer :: result 320 | result = min(x, y) 321 | end function 322 | 323 | pure function zero_integer() result(result) 324 | integer :: result 325 | result = 0 326 | end function 327 | 328 | pure function one_integer() result(result) 329 | integer :: result 330 | result = 1 331 | end function 332 | 333 | end module 334 | 335 | module Math_real_m 336 | 337 | implicit none 338 | private 339 | public :: add_real 340 | 341 | contains 342 | 343 | pure function add_real(x, y) result(result) 344 | real, intent(in) :: x, y 345 | real :: result 346 | result = x + y 347 | end function 348 | 349 | pure function minus_real(x, y) result(result) 350 | real, intent(in) :: x, y 351 | real :: result 352 | result = x - y 353 | end function 354 | 355 | pure function slash_real(x, y) result(result) 356 | real, intent(in) :: x, y 357 | real :: result 358 | result = x / y 359 | end function 360 | 361 | pure function max_real(x, y) result(result) 362 | real, intent(in) :: x, y 363 | real :: result 364 | result = max(x, y) 365 | end function 366 | 367 | pure function min_real(x, y) result(result) 368 | real, intent(in) :: x, y 369 | real :: result 370 | result = min(x, y) 371 | end function 372 | 373 | pure function zero_real() result(result) 374 | real :: result 375 | result = 0.0 376 | end function 377 | 378 | pure function one_real() result(result) 379 | real :: result 380 | result = 1.0 381 | end function 382 | 383 | end module 384 | 385 | module triple_m 386 | 387 | implicit none 388 | private 389 | public :: triple_tmpl 390 | 391 | requirement magma_r(T, plus_T) 392 | type, deferred :: T 393 | 394 | pure function plus_T(l, r) result(total) 395 | type(T), intent(in) :: l, r 396 | type(T) :: total 397 | end function 398 | end requirement 399 | 400 | template triple_tmpl(T, plus_T) 401 | require :: magma_r(T, plus_T) 402 | private 403 | public :: triple_l, triple_r 404 | contains 405 | pure function triple_l(t) result(result) 406 | type(T), intent(in) :: t 407 | type(T) :: result 408 | result = plus_T(plus_T(t, t), t) 409 | end function 410 | 411 | pure function triple_r(t) result(result) 412 | type(T), intent(in) :: t 413 | type(T) :: result 414 | result = plus_T(t, plus_T(t, t)) 415 | end function 416 | end template 417 | 418 | end module 419 | 420 | module use_triple_m 421 | 422 | use Math_integer_m 423 | use Math_real_m 424 | use triple_m 425 | 426 | contains 427 | 428 | subroutine test_add_triples() 429 | instantiate triple_tmpl(integer, add_integer), & 430 | only: triple_add_l => triple_l, & 431 | triple_add_r => triple_r 432 | integer :: tal, tar 433 | tal = triple_add_l(7) 434 | tar = triple_add_r(7) 435 | print *, "tal = ", tal, " tar = ", tar 436 | end subroutine 437 | 438 | subroutine test_minus_triples() 439 | instantiate triple_tmpl(real, minus_real), & 440 | only: triple_minus_l => triple_l, & 441 | triple_minus_r => triple_r 442 | real :: tml, tmr 443 | tml = triple_minus_l(7.0) 444 | tmr = triple_minus_r(7.0) 445 | print *, "tml = ", tml, " tmr = ", tmr 446 | end subroutine 447 | 448 | subroutine test_max_triples() 449 | instantiate triple_tmpl(real, max_real), & 450 | only: triple_max_l => triple_l, & 451 | triple_max_r => triple_r 452 | real :: tmaxl, tmaxr 453 | tmaxl = triple_max_l(7.0) 454 | tmaxr = triple_max_r(7.0) 455 | print *, "tmaxl =", tmaxl, " tmaxr =", tmaxr 456 | end subroutine 457 | 458 | end module 459 | 460 | program template_triple 461 | use use_triple_m 462 | 463 | call test_add_triples() 464 | call test_minus_triples() 465 | call test_max_triples() 466 | 467 | end program template_triple`, 468 | template_array_01b: `module template_array_01b_m 469 | 470 | implicit none 471 | private 472 | public :: test_template 473 | 474 | requirement r(t) 475 | type, deferred :: t 476 | end requirement 477 | 478 | template array_tmpl(t) 479 | require :: r(t) 480 | private 481 | public :: insert_t 482 | contains 483 | function insert_t(n, lst, i) result(r) 484 | integer, intent(in) :: n 485 | type(t), intent(in) :: lst(n), i 486 | type(t) :: r 487 | lst(1) = i 488 | r = lst(1) 489 | end function 490 | end template 491 | 492 | contains 493 | 494 | subroutine test_template() 495 | instantiate array_tmpl(integer), only: insert_int => insert_t 496 | integer :: a(1), i, r 497 | a(1) = 0 498 | i = 1 499 | print *, a(1) 500 | r = insert_int(size(a), a, i) 501 | print *, a(1) 502 | end subroutine 503 | 504 | end module 505 | 506 | program template_array_01b 507 | 508 | use template_array_01b_m 509 | implicit none 510 | 511 | call test_template() 512 | 513 | end`, 514 | template_array_02b: `module template_array_02b_math 515 | 516 | implicit none 517 | private 518 | public :: add_integer, zero_integer, add_real, zero_real 519 | 520 | contains 521 | 522 | pure function add_integer(x, y) result(r) 523 | integer, intent(in) :: x, y 524 | integer :: r 525 | r = x + y 526 | end function 527 | 528 | pure function zero_integer(x) result(r) 529 | integer, intent(in) :: x 530 | integer :: r 531 | r = 0 532 | end function 533 | 534 | pure function add_real(x, y) result(r) 535 | real, intent(in) :: x, y 536 | real :: r 537 | r = x + y 538 | end function 539 | 540 | pure function zero_real(x) result(r) 541 | real, intent(in) :: x 542 | real :: r 543 | r = 0 544 | end function 545 | 546 | end module 547 | 548 | module template_array_02b_m 549 | 550 | use template_array_02b_math 551 | implicit none 552 | private 553 | public :: test_template 554 | 555 | requirement operations(t, plus_t, zero_t) 556 | type, deferred :: t 557 | 558 | pure function plus_t(l, r) result(rs) 559 | type(t), intent(in) :: l, r 560 | type(t) :: rs 561 | end function 562 | 563 | pure function zero_t(l) result(rs) 564 | type(t), intent(in) :: l 565 | type(t) :: rs 566 | end function 567 | end requirement 568 | 569 | template array_tmpl(t, plus_t, zero_t) 570 | require :: operations(t, plus_t, zero_t) 571 | private 572 | public :: mysum_t 573 | contains 574 | function mysum_t(n, a) result(r) 575 | integer, intent(in) :: n 576 | type(t), intent(in) :: a(n) 577 | type(t) :: r 578 | integer :: i 579 | r = zero_t(a(1)) 580 | do i = 1, size(a) 581 | r = plus_t(r, a(i)) 582 | end do 583 | end function 584 | end template 585 | 586 | contains 587 | 588 | subroutine test_template() 589 | instantiate array_tmpl(integer, add_integer, zero_integer), only: mysum_integer => mysum_t 590 | integer :: a(10), i, s 591 | do i = 1, size(a) 592 | a(i) = i 593 | end do 594 | s = mysum_integer(size(a), a) 595 | print *, s 596 | end subroutine 597 | 598 | end module 599 | 600 | program template_array_02b 601 | 602 | use template_array_02b_m 603 | implicit none 604 | 605 | call test_template() 606 | 607 | end`, 608 | template_array_03: `module template_array_03_math 609 | 610 | implicit none 611 | private 612 | public :: add_integer, zero_integer, add_real, zero_real, mult_integer, mult_real 613 | 614 | contains 615 | 616 | pure function add_integer(x, y) result(r) 617 | integer, intent(in) :: x, y 618 | integer :: r 619 | r = x + y 620 | end function 621 | 622 | pure function zero_integer(x) result(r) 623 | integer, intent(in) :: x 624 | integer :: r 625 | r = 0 626 | end function 627 | 628 | pure function mult_integer(x, y) result(r) 629 | integer, intent(in) :: x, y 630 | integer :: r 631 | r = x * y 632 | end function 633 | 634 | pure function add_real(x, y) result(r) 635 | real, intent(in) :: x, y 636 | real :: r 637 | r = x + y 638 | end function 639 | 640 | pure function zero_real(x) result(r) 641 | real, intent(in) :: x 642 | real :: r 643 | r = 0 644 | end function 645 | 646 | pure function mult_real(x, y) result(r) 647 | real, intent(in) :: x, y 648 | real :: r 649 | r = x * y 650 | end function 651 | 652 | end module 653 | 654 | module template_array_03_m 655 | 656 | use template_array_03_math 657 | implicit none 658 | private 659 | public :: test_template 660 | 661 | requirement operations(t, plus_t, zero_t, mult_t) 662 | 663 | type, deferred :: t 664 | 665 | pure function plus_t(l, r) result(result) 666 | type(t), intent(in) :: l, r 667 | type(t) :: result 668 | end function 669 | 670 | pure function zero_t(x) result(result) 671 | type(t), intent(in) :: x 672 | type(t) :: result 673 | end function 674 | 675 | pure function mult_t(l, r) result(result) 676 | type(t), intent(in) :: l, r 677 | type(t) :: result 678 | end function 679 | 680 | end requirement 681 | ! 682 | template array_tmpl(t, plus_t, zero_t, mult_t) 683 | 684 | require :: operations(t, plus_t, zero_t, mult_t) 685 | private 686 | public :: mymatmul_t 687 | 688 | contains 689 | 690 | subroutine mymatmul_t(i, j, k, a, b, r) 691 | integer, parameter, intent(in) :: i, j, k 692 | type(t), intent(in) :: a(i,j), b(j,k) 693 | type(t) :: r(i,k) 694 | integer, parameter :: x = 1, y = 1, z = 1 695 | type(t) :: elem 696 | do x = 1, i 697 | do z = 1, k 698 | elem = zero_t(a(1,1)) 699 | do y = 1, j 700 | elem = plus_t(elem, mult_t(a(x,y), b(y,z))) 701 | end do 702 | r(x,z) = elem 703 | end do 704 | end do 705 | end subroutine 706 | 707 | end template 708 | 709 | contains 710 | 711 | subroutine test_template() 712 | integer :: arr(2,2) 713 | integer :: r(2,2) 714 | arr(1,1) = 1 715 | arr(1,2) = 1 716 | arr(2,1) = 0 717 | arr(2,2) = 1 718 | instantiate array_tmpl(integer, add_integer, zero_integer, mult_integer), & 719 | only: mymatmul_int => mymatmul_t 720 | call mymatmul_int(2, 2, 2, arr, arr, r) 721 | print *, r(1,1) 722 | print *, r(1,2) 723 | print *, r(2,1) 724 | print *, r(2,2) 725 | end subroutine 726 | 727 | end module 728 | 729 | program template_array_03 730 | 731 | use template_array_03_m 732 | implicit none 733 | 734 | call test_template() 735 | 736 | end`, 737 | template_array_04: `module reverse_m 738 | implicit none 739 | private 740 | public :: reverse_tmpl 741 | 742 | requirement default_behavior(t) 743 | type, deferred :: t 744 | end requirement 745 | 746 | template reverse_tmpl(t) 747 | require :: default_behavior(t) 748 | private 749 | public :: reverse 750 | contains 751 | subroutine swap(x, y) 752 | type(t), intent(inout) :: x, y 753 | type(t) :: tmp 754 | tmp = x 755 | x = y 756 | y = tmp 757 | end subroutine 758 | 759 | subroutine reverse(arr) 760 | type(t), intent(inout) :: arr(:) 761 | integer :: i, j 762 | do i = 1, size(arr)/2 763 | j = size(arr)+1-i 764 | call swap(arr(i), arr(j)) 765 | end do 766 | end subroutine 767 | end template 768 | 769 | contains 770 | 771 | subroutine test_reverse() 772 | instantiate reverse_tmpl(integer), & 773 | only: ireverse => reverse 774 | integer :: a(5) 775 | a = [1,2,3,4,5] 776 | call ireverse(a) 777 | print *, a 778 | if (a(1) /= 5) error stop 779 | if (a(5) /= 1) error stop 780 | end subroutine 781 | 782 | end module 783 | 784 | program main 785 | use reverse_m 786 | call test_reverse() 787 | end program` 788 | } 789 | } 790 | 791 | export default preinstalled_programs; 792 | --------------------------------------------------------------------------------