about summary refs log blame commit diff stats
path: root/html/schemer/index.html
blob: ebadf8395212b8c6243b02a4f0affbd41347325f (plain) (tree)








































































































































































































































                                                                                                  
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Scheme Interpreter with PDF</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            font-family: Arial, sans-serif;
        }
        #pdf-container {
            width: 100%;
            height: 67%;
            overflow: hidden;
        }
        #repl-container {
            width: 100%;
            height: 33%;
            display: flex;
            flex-direction: column;
            border-top: 1px solid #ccc;
            padding: 10px;
        }
        textarea {
            flex: 1;
            width: 100%;
            font-family: monospace;
            font-size: 16px;
            padding: 10px;
        }
        button {
            margin-top: 10px;
            padding: 10px;
            font-size: 16px;
        }
        #scheme-output {
            font-family: monospace;
            background-color: #f0f0f0;
            padding: 10px;
            margin-top: 10px;
            overflow-wrap: break-word;
        }
    </style>
</head>
<body>

    <div id="pdf-container">
        <embed src="tls.pdf" type="application/pdf" width="100%" height="100%">
    </div>

    <div id="repl-container">
        <textarea id="scheme-input" placeholder="Scheme here..."></textarea>
        <div id="scheme-output"></div>
        <button onclick="evaluateScheme()">Run Code</button>
    </div>

    <script>
        // Scheme interpreter (unchanged)
        function tokenizeScheme(input) {
            const tokens = [];
            let current = 0;

            const isWhitespace = (char) => /\s/.test(char);
            const isDigit = (char) => /[0-9]/.test(char);
            const isParen = (char) => char === '(' || char === ')';
            const isSymbolChar = (char) => /[a-zA-Z0-9\+\-\*\/\=\?\!\_]/.test(char);

            while (current < input.length) {
                let char = input[current];

                if (isWhitespace(char)) {
                    current++;
                    continue;
                }

                if (isParen(char)) {
                    tokens.push({ type: 'paren', value: char });
                    current++;
                    continue;
                }

                if (isDigit(char) || (char === '-' && isDigit(input[current + 1]))) {
                    let number = '';
                    while (isDigit(char) || char === '-') {
                        number += char;
                        char = input[++current];
                    }
                    tokens.push({ type: 'number', value: number });
                    continue;
                }

                if (isSymbolChar(char)) {
                    let symbol = '';
                    while (isSymbolChar(char)) {
                        symbol += char;
                        char = input[++current];
                    }
                    tokens.push({ type: 'symbol', value: symbol });
                    continue;
                }

                throw new Error(`Unexpected character: ${char}`);
            }

            return tokens;
        }

        function parseScheme(tokens) {
            let current = 0;

            function walk() {
                let token = tokens[current];

                if (token.type === 'number') {
                    current++;
                    return { type: 'NumberLiteral', value: Number(token.value) };
                }

                if (token.type === 'symbol') {
                    current++;
                    return { type: 'Symbol', value: token.value };
                }

                if (token.type === 'paren' && token.value === '(') {
                    current++;
                    const node = { type: 'List', value: [] };

                    while (!(tokens[current].type === 'paren' && tokens[current].value === ')')) {
                        node.value.push(walk());
                    }

                    current++; // Skip closing ')'
                    return node;
                }

                throw new Error(`Unexpected token: ${token.type}`);
            }

            return walk();
        }

        const globalEnv = {
            '+': (...args) => args.reduce((acc, curr) => acc + curr),
            '-': (...args) => args.reduce((acc, curr) => acc - curr),
            '*': (...args) => args.reduce((acc, curr) => acc * curr),
            '/': (a, b) => a / b,
            'eq?': (...args) => args.every((val, i, arr) => val === arr[0]),
            'car': (list) => list[0],
            'cdr': (list) => list.slice(1),
            'cons': (a, b) => [a].concat(b),
            'null?': (list) => list.length === 0,
        };

        function evaluate(node, env = globalEnv) {
            if (node.type === 'NumberLiteral') {
                return node.value;
            }

            if (node.type === 'Symbol') {
                if (env[node.value] !== undefined) {
                    return env[node.value];
                }
                throw new Error(`Undefined symbol: ${node.value}`);
            }

            if (node.type === 'List') {
                const [first, ...rest] = node.value;

                if (first.type === 'Symbol') {
                    const operator = first.value;

                    if (operator === 'define') {
                        const [symbol, expr] = rest;
                        env[symbol.value] = evaluate(expr, env);
                        return;
                    }

                    if (operator === 'lambda') {
                        const [params, body] = rest;

                        return function (...args) {
                            const lambdaEnv = { ...env };
                            params.value.forEach((param, i) => {
                                lambdaEnv[param.value] = args[i];
                            });
                            return evaluate(body, lambdaEnv);
                        };
                    }

                    if (operator === 'if') {
                        const [test, consequent, alternate] = rest;
                        const condition = evaluate(test, env);
                        return condition ? evaluate(consequent, env) : evaluate(alternate, env);
                    }
                }

                const func = evaluate(first, env);

                if (typeof func !== 'function') {
                    throw new Error(`Expected a function but got: ${func}`);
                }

                const args = rest.map(arg => evaluate(arg, env));
                return func(...args);
            }

            throw new Error(`Unexpected node type: ${node.type}`);
        }

        function evalScheme(input) {
            const tokens = tokenizeScheme(input);
            const ast = parseScheme(tokens);
            return evaluate(ast);
        }

        // Function to evaluate the input in the REPL
        function evaluateScheme() {
            const input = document.getElementById('scheme-input').value;
            let output;
            try {
                output = evalScheme(input);
            } catch (error) {
                output = `Error: ${error.message}`;
            }
            document.getElementById('scheme-output').innerText = JSON.stringify(output, null, 2);
        }
    </script>

</body>
</html>